<?xml version="1.0" encoding="UTF-8"?>
<rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/"
    xmlns:atom="http://www.w3.org/2005/Atom" xmlns:media="http://search.yahoo.com/mrss/" version="2.0">
    <channel>
        
        <title>
            <![CDATA[ animation - freeCodeCamp.org ]]>
        </title>
        <description>
            <![CDATA[ Browse thousands of programming tutorials written by experts. Learn Web Development, Data Science, DevOps, Security, and get developer career advice. ]]>
        </description>
        <link>https://www.freecodecamp.org/news/</link>
        <image>
            <url>https://cdn.freecodecamp.org/universal/favicons/favicon.png</url>
            <title>
                <![CDATA[ animation - freeCodeCamp.org ]]>
            </title>
            <link>https://www.freecodecamp.org/news/</link>
        </image>
        <generator>Eleventy</generator>
        <lastBuildDate>Sat, 23 May 2026 22:20:28 +0000</lastBuildDate>
        <atom:link href="https://www.freecodecamp.org/news/tag/animation/rss.xml" rel="self" type="application/rss+xml" />
        <ttl>60</ttl>
        
            <item>
                <title>
                    <![CDATA[ How to Create Fluid Animations with React Native Reanimated v4 ]]>
                </title>
                <description>
                    <![CDATA[ Reanimated 4 brings Cascading Style Sheets (CSS) animations to React Native while keeping full backward compatibility with its worklet-based API. You can now build 60+ frames-per-second (FPS) animations using familiar web syntax, or drop down to work... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-create-fluid-animations-with-react-native-reanimated-v4/</link>
                <guid isPermaLink="false">691b3eab5aa173ac953652e2</guid>
                
                    <category>
                        <![CDATA[ React Native ]]>
                    </category>
                
                    <category>
                        <![CDATA[ React ]]>
                    </category>
                
                    <category>
                        <![CDATA[ react native reanimated ]]>
                    </category>
                
                    <category>
                        <![CDATA[ animation ]]>
                    </category>
                
                    <category>
                        <![CDATA[ JavaScript ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Balogun Wahab ]]>
                </dc:creator>
                <pubDate>Mon, 17 Nov 2025 15:26:35 +0000</pubDate>
                <media:content url="https://cdn.hashnode.com/res/hashnode/image/upload/v1763052228638/4416e81d-b76e-4c40-987e-0aff1d82ff7b.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Reanimated 4 brings Cascading Style Sheets (CSS) animations to React Native while keeping full backward compatibility with its worklet-based API. You can now build 60+ frames-per-second (FPS) animations using familiar web syntax, or drop down to worklets for gesture-driven interactions.</p>
<p>The library requires React Native's New Architecture (Fabric), so you'll need version 0.76 or newer.</p>
<p>In this tutorial, you'll learn:</p>
<ul>
<li><p>How to use CSS transitions for state-driven animations</p>
</li>
<li><p>When to use worklets for gesture and scroll interactions</p>
</li>
<li><p>How to migrate from Reanimated 3 to 4</p>
</li>
<li><p>Practical patterns for collapsing headers, bottom sheets, and carousels</p>
</li>
<li><p>Performance optimization techniques</p>
</li>
</ul>
<h3 id="heading-prerequisites">Prerequisites</h3>
<p>You should have:</p>
<ul>
<li><p>React Native 0.76+ with New Architecture enabled</p>
</li>
<li><p>Basic React hooks knowledge (useState, useEffect)</p>
</li>
<li><p>Node.js and npm or yarn are installed</p>
</li>
</ul>
<h2 id="heading-table-of-contents">Table of Contents</h2>
<ul>
<li><p><a class="post-section-overview" href="#heading-installation-and-setup">Installation and Setup</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-understanding-the-two-approaches">Understanding the Two Approaches (CSS Animations and Worklets)</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-migrate-from-reanimated-version-3-to-version-4">How to Migrate from Reanimated Version 3 to Version 4</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-css-animations-tutorial">CSS Animations Tutorial</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-worklets-tutorial">Worklets Tutorial</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-real-world-patterns">Real-World Patterns</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-performance-optimizations">Performance Optimizations</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-debugging-tips">Debugging Tips</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-conclusion">Conclusion</a></p>
</li>
</ul>
<h2 id="heading-installation-and-setup">Installation and Setup</h2>
<p>To get started, you'll need to install the required packages:</p>
<pre><code class="lang-bash"><span class="hljs-comment"># For Expo</span>
npx expo install react-native-reanimated react-native-worklets

<span class="hljs-comment"># For React Native CLI  </span>
npm install react-native-reanimated react-native-worklets
<span class="hljs-built_in">cd</span> ios &amp;&amp; pod install &amp;&amp; <span class="hljs-built_in">cd</span> ..
</code></pre>
<p>Update <code>babel.config.js</code> (the plugin must be last):</p>
<pre><code class="lang-javascript"><span class="hljs-built_in">module</span>.exports = {
  <span class="hljs-attr">presets</span>: [<span class="hljs-string">'module:metro-react-native-babel-preset'</span>],
  <span class="hljs-attr">plugins</span>: [
    <span class="hljs-string">'react-native-worklets/plugin'</span>, <span class="hljs-comment">// Must be last</span>
  ],
};
</code></pre>
<p>Then clear the cache and rebuild:</p>
<pre><code class="lang-bash">npm start -- --reset-cache
npx react-native run-ios
</code></pre>
<h2 id="heading-understanding-the-two-approaches">Understanding the Two Approaches</h2>
<p>React Native Reanimated is an animation library that runs animations on the native thread instead of the JavaScript thread. This means your animations stay smooth even when your JavaScript code is busy processing data or handling user interactions.</p>
<p>Unlike React Native's built-in Animated API, Reanimated executes animation logic directly on the UI thread. This eliminates the performance bottleneck caused by communication between JavaScript and native code, which enables Reanimated to maintain 60 FPS even during complex operations.</p>
<p>Reanimated 4 offers two animation systems, each designed for different use cases.</p>
<h3 id="heading-css-animations">CSS Animations</h3>
<p>CSS animations work declaratively, meaning you describe what you want to happen rather than how to make it happen. You define which properties should animate (like width, color, or opacity), specify the timing and easing, then simply change the values through React state updates. Reanimated automatically handles the animation between the old and new values.</p>
<p>This approach excels at predictable, state-driven animations where you know both the starting and ending states. It's ideal for:</p>
<ul>
<li><p>Showing and hiding UI elements (modals, tooltips, notifications)</p>
</li>
<li><p>Expanding and collapsing content (accordions, dropdown menus)</p>
</li>
<li><p>Visual feedback for state changes (button hover effects, selection highlights)</p>
</li>
<li><p>Loading indicators and progress animations</p>
</li>
<li><p>Color and opacity transitions</p>
</li>
</ul>
<h3 id="heading-worklets">Worklets</h3>
<p>Worklets take a different approach by giving you imperative, frame-by-frame control over animations. They run on the UI thread and use "shared values" – special variables that can be accessed and modified from both JavaScript and native code without any communication overhead.</p>
<p>Worklets are essential for interactive animations that need to respond in real-time to user input or continuous data streams. They're best for:</p>
<ul>
<li><p>Gesture-driven interactions (drag-and-drop, swipe-to-dismiss, pinch-to-zoom)</p>
</li>
<li><p>Scroll-linked effects (parallax images, collapsing headers, sticky elements)</p>
</li>
<li><p>Physics-based animations (spring effects, momentum scrolling)</p>
</li>
<li><p>Sensor-based animations (responding to device orientation)</p>
</li>
<li><p>Any animation requiring dynamic, real-time control</p>
</li>
</ul>
<p>Now that you understand the two approaches Reanimated offers, let's look at how to migrate from version 3 if you're already using the library.</p>
<h2 id="heading-how-to-migrate-from-reanimated-version-3-to-version-4">How to Migrate from Reanimated Version 3 to Version 4</h2>
<p>If you're currently using Reanimated 3, you'll be happy to know that version 4 maintains backward compatibility. Your existing animations using worklets, shared values, and <code>useAnimatedStyle</code> will continue to work without modification.</p>
<p>But version 4 introduces some architectural changes and removes deprecated APIs, so you'll need to make a few updates to your project configuration and code. Let's walk through the migration process step by step.</p>
<h3 id="heading-what-changed-in-version-4">What Changed in Version 4</h3>
<p>The most significant change is that worklets have been extracted into a separate package called <code>react-native-worklets-core</code>. This modular approach allows other libraries beyond Reanimated to leverage worklet functionality.</p>
<p>Because of this separation, you'll need to update your Babel configuration. Change the plugin from <code>react-native-reanimated/plugin</code> to <code>react-native-worklets/plugin</code>.</p>
<p>Version 4 also exclusively supports React Native's New Architecture (Fabric). The old Paper renderer is no longer compatible. If your project hasn't migrated to the New Architecture yet, you'll need to either upgrade to React Native 0.76+ (which has New Architecture enabled by default) or stay on Reanimated 3.x until you're ready to make that transition.</p>
<h3 id="heading-removed-apis">Removed APIs</h3>
<p>Several APIs that were deprecated in version 3 have been removed in version 4. Here's what you need to replace:</p>
<ul>
<li><p><code>useAnimatedGestureHandler</code> → Use the <code>Gesture</code> API from react-native-gesture-handler 2.x instead</p>
</li>
<li><p><code>useWorkletCallback</code> → Use <code>useCallback</code> with the <code>'worklet'</code> directive</p>
</li>
<li><p><code>combineTransition</code> → Use <code>EntryExitTransition.entering().exiting()</code></p>
</li>
</ul>
<p>The <code>useScrollViewOffset</code> hook has been renamed to <code>useScrollOffset</code>. The old name still works but is deprecated, so update your code to use the new name.</p>
<h3 id="heading-spring-configuration-change">Spring Configuration Change</h3>
<p>The spring animation configuration has changed to feel more natural. The <code>duration</code> parameter now represents "perceptual duration" rather than exact milliseconds. The actual animation runs approximately 1.5 times longer than the specified duration, creating springs that feel more organic and less mechanical.</p>
<pre><code class="lang-javascript"><span class="hljs-comment">// Version 3</span>
withSpring(<span class="hljs-number">100</span>, { <span class="hljs-attr">duration</span>: <span class="hljs-number">300</span> }) <span class="hljs-comment">// Runs for exactly 300ms</span>

<span class="hljs-comment">// Version 4  </span>
withSpring(<span class="hljs-number">100</span>, { <span class="hljs-attr">duration</span>: <span class="hljs-number">200</span> }) <span class="hljs-comment">// Runs for approximately 300ms</span>
</code></pre>
<p>If you need to maintain the exact timing from version 3, divide your duration values by 1.5.</p>
<h3 id="heading-step-by-step-migration-process">Step-by-Step Migration Process</h3>
<p>Here's how to migrate your project from Reanimated 3 to version 4:</p>
<p><strong>Step 1:</strong> Verify your project is using React Native 0.76 or newer with New Architecture enabled. Check your iOS Podfile for <code>ENV['RCT_NEW_ARCH_ENABLED'] = '1'</code> and your Android gradle.properties for <code>newArchEnabled=true</code>.</p>
<p><strong>Step 2:</strong> Install the new versions of Reanimated and the worklets package:</p>
<pre><code class="lang-bash">npm install react-native-reanimated@^4.1.0 react-native-worklets@^0.5.0
</code></pre>
<p><strong>Step 3:</strong> Update your <code>babel.config.js</code> to use the new worklets plugin:</p>
<pre><code class="lang-javascript"><span class="hljs-built_in">module</span>.exports = {
  <span class="hljs-attr">plugins</span>: [
    <span class="hljs-string">'react-native-worklets/plugin'</span>, <span class="hljs-comment">// Changed from react-native-reanimated/plugin</span>
  ],
};
</code></pre>
<p><strong>Step 4:</strong> Search your codebase for the removed APIs and replace them:</p>
<ul>
<li><p>Replace <code>useAnimatedGestureHandler</code> with the <code>Gesture</code> API</p>
</li>
<li><p>Replace <code>useWorkletCallback</code> with <code>useCallback</code> and add <code>'worklet'</code> directive</p>
</li>
<li><p>Replace <code>combineTransition</code> with <code>EntryExitTransition.entering().exiting()</code></p>
</li>
<li><p>Rename <code>useScrollViewOffset</code> to <code>useScrollOffset</code></p>
</li>
</ul>
<p><strong>Step 5:</strong> Rebuild your native apps:</p>
<pre><code class="lang-bash"><span class="hljs-built_in">cd</span> ios &amp;&amp; pod install &amp;&amp; <span class="hljs-built_in">cd</span> ..
npx react-native run-ios
<span class="hljs-comment"># or for Android</span>
npx react-native run-android
</code></pre>
<p>After completing these steps, your app should be running on Reanimated 4 with all your existing animations working as before. You're now ready to start using the new CSS animation features alongside your existing worklet-based animations. In the next section, you'll learn how to build animations using the CSS syntax.</p>
<h2 id="heading-css-animations-tutorial">CSS Animations Tutorial</h2>
<p>CSS animations provide a clean, declarative way to handle transitions that are triggered by state changes. Instead of manually managing animation values, you simply declare which properties should animate and how, then update your component state – Reanimated handles the rest.</p>
<p>This approach is particularly powerful for animations where you know the start and end states ahead of time. It's perfect for UI elements that toggle between different visual states, like modals appearing and disappearing, buttons providing feedback on press, or content expanding and collapsing.</p>
<h3 id="heading-basic-transitions">Basic Transitions</h3>
<p>A transition animates the change between two property values. When you specify a property that should transition, Reanimated automatically interpolates between the old and new values over the specified duration.</p>
<p>Let's look at an expandable card that grows when tapped:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> React, { useState } <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>;
<span class="hljs-keyword">import</span> { Pressable, Text } <span class="hljs-keyword">from</span> <span class="hljs-string">'react-native'</span>;
<span class="hljs-keyword">import</span> Animated <span class="hljs-keyword">from</span> <span class="hljs-string">'react-native-reanimated'</span>;

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">ExpandableCard</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> [expanded, setExpanded] = useState(<span class="hljs-literal">false</span>);

  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">Pressable</span> <span class="hljs-attr">onPress</span>=<span class="hljs-string">{()</span> =&gt;</span> setExpanded(!expanded)}&gt;
      <span class="hljs-tag">&lt;<span class="hljs-name">Animated.View</span> <span class="hljs-attr">style</span>=<span class="hljs-string">{{</span>
        <span class="hljs-attr">width:</span> <span class="hljs-attr">expanded</span> ? <span class="hljs-attr">300</span> <span class="hljs-attr">:</span> <span class="hljs-attr">200</span>,
        <span class="hljs-attr">height:</span> <span class="hljs-attr">expanded</span> ? <span class="hljs-attr">200</span> <span class="hljs-attr">:</span> <span class="hljs-attr">100</span>,
        <span class="hljs-attr">backgroundColor:</span> <span class="hljs-attr">expanded</span> ? '#<span class="hljs-attr">4ade80</span>' <span class="hljs-attr">:</span> '#<span class="hljs-attr">86efac</span>',
        <span class="hljs-attr">transitionProperty:</span> ['<span class="hljs-attr">width</span>', '<span class="hljs-attr">height</span>', '<span class="hljs-attr">backgroundColor</span>'],
        <span class="hljs-attr">transitionDuration:</span> <span class="hljs-attr">300</span>,
        <span class="hljs-attr">transitionTimingFunction:</span> '<span class="hljs-attr">ease-in-out</span>',
      }}&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">Text</span>&gt;</span>Tap to toggle<span class="hljs-tag">&lt;/<span class="hljs-name">Text</span>&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">Animated.View</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">Pressable</span>&gt;</span></span>
  );
}
</code></pre>
<p>Here's what's happening: The card's width, height, and background color are controlled by the <code>expanded</code> state. The <code>transitionProperty</code> array tells Reanimated which properties to animate. When <code>expanded</code> changes, Reanimated smoothly animates from the current values to the new values over 300 milliseconds, using an ease-in-out timing function that starts slow, speeds up, then slows down again.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1762274975831/7e25aa04-24b8-43eb-9db0-a3c088c44132.gif" alt="7e25aa04-24b8-43eb-9db0-a3c088c44132" class="image--center mx-auto" width="600" height="400" loading="lazy"></p>
<h3 id="heading-keyframe-animations">Keyframe Animations</h3>
<p>While transitions handle changes between two states, keyframe animations let you define multi-step sequences with precise control over each stage. You create an object where each key represents a percentage of the animation timeline, and the value defines what properties should look like at that point.</p>
<p>Here's a pulsing badge that scales up and fades slightly, then returns to normal:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> pulseAnimation = {
  <span class="hljs-string">'0%'</span>: { <span class="hljs-attr">scale</span>: <span class="hljs-number">1</span>, <span class="hljs-attr">opacity</span>: <span class="hljs-number">1</span> },
  <span class="hljs-string">'50%'</span>: { <span class="hljs-attr">scale</span>: <span class="hljs-number">1.05</span>, <span class="hljs-attr">opacity</span>: <span class="hljs-number">0.8</span> },
  <span class="hljs-string">'100%'</span>: { <span class="hljs-attr">scale</span>: <span class="hljs-number">1</span>, <span class="hljs-attr">opacity</span>: <span class="hljs-number">1</span> },
};

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">PulsingBadge</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">Animated.View</span> <span class="hljs-attr">style</span>=<span class="hljs-string">{{</span>
      <span class="hljs-attr">width:</span> <span class="hljs-attr">50</span>,
      <span class="hljs-attr">height:</span> <span class="hljs-attr">50</span>,
      <span class="hljs-attr">borderRadius:</span> <span class="hljs-attr">25</span>,
      <span class="hljs-attr">backgroundColor:</span> '#<span class="hljs-attr">ef4444</span>',
      <span class="hljs-attr">animationName:</span> <span class="hljs-attr">pulseAnimation</span>,
      <span class="hljs-attr">animationDuration:</span> <span class="hljs-attr">2000</span>,
      <span class="hljs-attr">animationIterationCount:</span> '<span class="hljs-attr">infinite</span>',
    }} /&gt;</span></span>
  );
}
</code></pre>
<p>The animation starts at 0% (normal size and opacity), grows and fades at the 50% mark, then returns to the original state at 100%. By setting <code>animationIterationCount</code> to 'infinite', the animation loops continuously. This creates the pulsing effect you often see on notification badges or live indicators.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1762274903470/d10d856f-03b8-4d6c-b616-22cbea3434c2.gif" alt="d10d856f-03b8-4d6c-b616-22cbea3434c2" class="image--center mx-auto" width="600" height="400" loading="lazy"></p>
<h3 id="heading-built-in-animations">Built-in Animations</h3>
<p>Reanimated includes a collection of pre-built animations for common entrance and exit effects. These save you from writing animation configurations for standard patterns like fading, sliding, and zooming.</p>
<p>Here's a modal that fades in when shown and fades out when hidden:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> { FadeIn, FadeOut } <span class="hljs-keyword">from</span> <span class="hljs-string">'react-native-reanimated'</span>;

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Modal</span>(<span class="hljs-params">{ visible, children }</span>) </span>{
  <span class="hljs-keyword">if</span> (!visible) <span class="hljs-keyword">return</span> <span class="hljs-literal">null</span>;

  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">Animated.View</span> 
      <span class="hljs-attr">entering</span>=<span class="hljs-string">{FadeIn.duration(300)}</span>
      <span class="hljs-attr">exiting</span>=<span class="hljs-string">{FadeOut.duration(200)}</span>
    &gt;</span>
      {children}
    <span class="hljs-tag">&lt;/<span class="hljs-name">Animated.View</span>&gt;</span></span>
  );
}
</code></pre>
<p>The <code>entering</code> prop automatically applies the fade-in animation when the component mounts, and <code>exiting</code> applies the fade-out before unmounting. Other commonly used built-in animations include <code>SlideInRight</code>, <code>SlideOutLeft</code> (for drawer-style entrances), and <code>ZoomIn</code>, <code>ZoomOut</code> (for attention-grabbing pop-ins).</p>
<p>Now that you understand CSS animations for state-driven transitions, let's explore worklets for creating interactive animations that respond to user input in real-time.</p>
<h2 id="heading-worklets-tutorial">Worklets Tutorial</h2>
<p>While CSS animations excel at predefined state transitions, many animations need to respond dynamically to user input. This is where worklets come in. Worklets give you frame-by-frame control over animations, allowing them to follow gestures, scroll position, or any other real-time input source.</p>
<p>Interactive animations differ from CSS animations in that they don't have predefined start and end states. Instead, they continuously update based on user input. For example, a draggable element needs to follow your finger precisely as you move it – there's no way to know ahead of time where you'll drag it. This requires imperative control, where you directly manipulate animation values in response to events.</p>
<h3 id="heading-basic-worklet-animation">Basic Worklet Animation</h3>
<p>Shared values are the foundation of worklet-based animations. They're special variables that exist simultaneously in both the JavaScript and UI threads, allowing you to update them from JavaScript while the UI thread reads them to update the display – all without any communication overhead.</p>
<p>Here's a button that scales down when pressed and bounces back when released:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> Animated, { 
  useSharedValue, 
  useAnimatedStyle, 
  withSpring 
} <span class="hljs-keyword">from</span> <span class="hljs-string">'react-native-reanimated'</span>;
<span class="hljs-keyword">import</span> { Pressable } <span class="hljs-keyword">from</span> <span class="hljs-string">'react-native'</span>;

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">BouncyButton</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> scale = useSharedValue(<span class="hljs-number">1</span>);

  <span class="hljs-keyword">const</span> animatedStyle = useAnimatedStyle(<span class="hljs-function">() =&gt;</span> ({
    <span class="hljs-attr">transform</span>: [{ <span class="hljs-attr">scale</span>: scale.value }],
  }));

  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">Pressable</span>
      <span class="hljs-attr">onPressIn</span>=<span class="hljs-string">{()</span> =&gt;</span> { scale.value = withSpring(0.9); }}
      onPressOut={() =&gt; { scale.value = withSpring(1); }}
    &gt;
      <span class="hljs-tag">&lt;<span class="hljs-name">Animated.View</span> <span class="hljs-attr">style</span>=<span class="hljs-string">{[styles.button,</span> <span class="hljs-attr">animatedStyle</span>]}&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">Text</span>&gt;</span>Press Me<span class="hljs-tag">&lt;/<span class="hljs-name">Text</span>&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">Animated.View</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">Pressable</span>&gt;</span></span>
  );
}
</code></pre>
<p>The <code>useSharedValue(1)</code> creates a shared value initialized to 1 (normal scale). The <code>useAnimatedStyle</code> hook creates a style object that depends on this shared value and runs on the UI thread. When you press the button, <code>scale.value = withSpring(0.9)</code> updates the shared value, and <code>withSpring</code> creates a spring animation to the new value. The <code>useAnimatedStyle</code> hook automatically re-runs, updating the transform with the new scale value.</p>
<h3 id="heading-gesture-animations">Gesture Animations</h3>
<p>Gestures require even tighter integration between user input and animation. The react-native-gesture-handler library provides high-performance gesture recognition that works seamlessly with Reanimated.</p>
<p>First, install the gesture handler:</p>
<pre><code class="lang-bash">npm install react-native-gesture-handler
<span class="hljs-built_in">cd</span> ios &amp;&amp; pod install &amp;&amp; <span class="hljs-built_in">cd</span> ..
</code></pre>
<p>Next, you need to wrap your app with <code>GestureHandlerRootView</code>. This component sets up the gesture handling system at the root of your application. Without it, gestures won't work. Think of it as activating the gesture system for your entire app:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> { GestureHandlerRootView } <span class="hljs-keyword">from</span> <span class="hljs-string">'react-native-gesture-handler'</span>;

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">App</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">GestureHandlerRootView</span> <span class="hljs-attr">style</span>=<span class="hljs-string">{{</span> <span class="hljs-attr">flex:</span> <span class="hljs-attr">1</span> }}&gt;</span>
      {/* Your app content goes here */}
    <span class="hljs-tag">&lt;/<span class="hljs-name">GestureHandlerRootView</span>&gt;</span></span>
  );
}
</code></pre>
<p>Now you can create gesture-driven animations. Here's a box you can drag around the screen that springs back to center when released:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> { Gesture, GestureDetector } <span class="hljs-keyword">from</span> <span class="hljs-string">'react-native-gesture-handler'</span>;

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">DraggableBox</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> offsetX = useSharedValue(<span class="hljs-number">0</span>);
  <span class="hljs-keyword">const</span> offsetY = useSharedValue(<span class="hljs-number">0</span>);

  <span class="hljs-keyword">const</span> pan = Gesture.Pan()
    .onChange(<span class="hljs-function">(<span class="hljs-params">event</span>) =&gt;</span> {
      offsetX.value += event.changeX;
      offsetY.value += event.changeY;
    })
    .onEnd(<span class="hljs-function">() =&gt;</span> {
      offsetX.value = withSpring(<span class="hljs-number">0</span>);
      offsetY.value = withSpring(<span class="hljs-number">0</span>);
    });

  <span class="hljs-keyword">const</span> animatedStyle = useAnimatedStyle(<span class="hljs-function">() =&gt;</span> ({
    <span class="hljs-attr">transform</span>: [
      { <span class="hljs-attr">translateX</span>: offsetX.value },
      { <span class="hljs-attr">translateY</span>: offsetY.value },
    ],
  }));

  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">GestureDetector</span> <span class="hljs-attr">gesture</span>=<span class="hljs-string">{pan}</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">Animated.View</span> <span class="hljs-attr">style</span>=<span class="hljs-string">{[styles.box,</span> <span class="hljs-attr">animatedStyle</span>]} /&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">GestureDetector</span>&gt;</span></span>
  );
}
</code></pre>
<p>The <code>Gesture.Pan()</code> creates a pan gesture recognizer. The <code>.onChange()</code> callback fires continuously while you're dragging – <code>event.changeX</code> and <code>event.changeY</code> tell you how much the finger moved since the last frame. By adding these values to the offsets, the box follows your finger. When you lift your finger, <code>.onEnd()</code> fires and springs the box back to the center (0, 0).</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1762275456257/3a536406-d678-46eb-9cfe-f689428d3412.gif" alt="3a536406-d678-46eb-9cfe-f689428d3412" class="image--center mx-auto" width="600" height="400" loading="lazy"></p>
<h3 id="heading-scroll-linked-animations">Scroll-Linked Animations</h3>
<p>Another common use case for worklets is creating effects that respond to scroll position, like headers that shrink as you scroll down or parallax backgrounds.</p>
<p>Here's a header that collapses as you scroll:</p>
<pre><code class="lang-javascript"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">ParallaxHeader</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> scrollY = useSharedValue(<span class="hljs-number">0</span>);

  <span class="hljs-keyword">const</span> scrollHandler = useAnimatedScrollHandler({
    <span class="hljs-attr">onScroll</span>: <span class="hljs-function">(<span class="hljs-params">event</span>) =&gt;</span> {
      scrollY.value = event.contentOffset.y;
    },
  });

  <span class="hljs-keyword">const</span> headerStyle = useAnimatedStyle(<span class="hljs-function">() =&gt;</span> {
    <span class="hljs-keyword">const</span> height = interpolate(
      scrollY.value,
      [<span class="hljs-number">0</span>, <span class="hljs-number">150</span>],
      [<span class="hljs-number">200</span>, <span class="hljs-number">60</span>],
      <span class="hljs-string">'clamp'</span>
    );

    <span class="hljs-keyword">return</span> { height };
  });

  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">Animated.View</span> <span class="hljs-attr">style</span>=<span class="hljs-string">{[styles.header,</span> <span class="hljs-attr">headerStyle</span>]}&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">Text</span>&gt;</span>Header<span class="hljs-tag">&lt;/<span class="hljs-name">Text</span>&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">Animated.View</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">Animated.ScrollView</span>
        <span class="hljs-attr">onScroll</span>=<span class="hljs-string">{scrollHandler}</span>
        <span class="hljs-attr">scrollEventThrottle</span>=<span class="hljs-string">{16}</span>
      &gt;</span>
        {/* Content */}
      <span class="hljs-tag">&lt;/<span class="hljs-name">Animated.ScrollView</span>&gt;</span>
    <span class="hljs-tag">&lt;/&gt;</span></span>
  );
}
</code></pre>
<p>The <code>useAnimatedScrollHandler</code> creates a scroll event handler that runs on the UI thread. Every time you scroll, it updates <code>scrollY</code> with the current scroll position. The <code>interpolate</code> function maps the scroll position to the header height – when scrollY is 0 (top of the scroll), height is 200. When scrollY reaches 150, height is 60. The 'clamp' option prevents the height from going outside this range.</p>
<p>With these fundamentals of CSS animations and worklets covered, let's look at how to apply them to common real-world scenarios.</p>
<h2 id="heading-real-world-patterns">Real-World Patterns</h2>
<p>Now that you understand both CSS animations and worklets, let's combine them to build three patterns you'll frequently encounter in production apps. These examples demonstrate when to use each animation approach and how to structure your code for maintainability.</p>
<p>In this section, you'll learn how to build a collapsing header that shrinks as users scroll (using worklets for scroll tracking), a bottom sheet that responds to drag gestures (using worklets for gesture control), and a swipe-to-delete interaction for list items (combining worklets for gesture detection with animations for the deletion effect).</p>
<h3 id="heading-collapsing-header">Collapsing Header</h3>
<p>A collapsing header is a navigation bar that starts tall and shrinks as you scroll down. This pattern is popular because it maximizes content space while keeping navigation accessible. You'll use worklets here because the animation needs to follow the scroll position in real-time.</p>
<pre><code class="lang-javascript"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">CollapsibleHeader</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> scrollY = useSharedValue(<span class="hljs-number">0</span>);
  <span class="hljs-keyword">const</span> HEADER_MAX = <span class="hljs-number">200</span>;
  <span class="hljs-keyword">const</span> HEADER_MIN = <span class="hljs-number">60</span>;

  <span class="hljs-keyword">const</span> scrollHandler = useAnimatedScrollHandler({
    <span class="hljs-attr">onScroll</span>: <span class="hljs-function">(<span class="hljs-params">event</span>) =&gt;</span> {
      scrollY.value = event.contentOffset.y;
    },
  });

  <span class="hljs-keyword">const</span> headerStyle = useAnimatedStyle(<span class="hljs-function">() =&gt;</span> ({
    <span class="hljs-attr">height</span>: interpolate(
      scrollY.value,
      [<span class="hljs-number">0</span>, HEADER_MAX - HEADER_MIN],
      [HEADER_MAX, HEADER_MIN],
      <span class="hljs-string">'clamp'</span>
    ),
  }));

  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">View</span> <span class="hljs-attr">style</span>=<span class="hljs-string">{{</span> <span class="hljs-attr">flex:</span> <span class="hljs-attr">1</span> }}&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">Animated.View</span> <span class="hljs-attr">style</span>=<span class="hljs-string">{[styles.header,</span> <span class="hljs-attr">headerStyle</span>]}&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">Text</span>&gt;</span>My App<span class="hljs-tag">&lt;/<span class="hljs-name">Text</span>&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">Animated.View</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">Animated.ScrollView</span>
        <span class="hljs-attr">onScroll</span>=<span class="hljs-string">{scrollHandler}</span>
        <span class="hljs-attr">scrollEventThrottle</span>=<span class="hljs-string">{16}</span>
      &gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">View</span> <span class="hljs-attr">style</span>=<span class="hljs-string">{{</span> <span class="hljs-attr">height:</span> <span class="hljs-attr">1000</span>, <span class="hljs-attr">padding:</span> <span class="hljs-attr">16</span> }}&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">Text</span>&gt;</span>Scroll to see header collapse<span class="hljs-tag">&lt;/<span class="hljs-name">Text</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">View</span>&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">Animated.ScrollView</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">View</span>&gt;</span></span>
  );
}
</code></pre>
<p>This pattern tracks scroll position in <code>scrollY</code> and uses <code>interpolate</code> to map it to header height. When you're at the top (scrollY = 0), the header is 200 pixels tall. As you scroll down 140 pixels, the header shrinks to 60 pixels. The animation happens on every frame as you scroll, which is why worklets are necessary – CSS animations couldn't track scroll position this smoothly.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1762326945758/044ca9d6-dd6e-4891-b9f4-3a4dc8590b58.gif" alt="044ca9d6-dd6e-4891-b9f4-3a4dc8590b58" class="image--center mx-auto" width="600" height="400" loading="lazy"></p>
<h3 id="heading-bottom-sheet">Bottom Sheet</h3>
<p>A bottom sheet is a panel that slides up from the bottom of the screen, commonly used for action menus, filters, or additional content. Users can drag it to different heights or dismiss it with a swipe down. This requires worklets because it needs frame-by-frame gesture tracking.</p>
<pre><code class="lang-javascript"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">BottomSheet</span>(<span class="hljs-params">{ children }</span>) </span>{
  <span class="hljs-keyword">const</span> translateY = useSharedValue(<span class="hljs-number">300</span>);
  <span class="hljs-keyword">const</span> context = useSharedValue({ <span class="hljs-attr">y</span>: <span class="hljs-number">0</span> });

  <span class="hljs-keyword">const</span> pan = Gesture.Pan()
    .onStart(<span class="hljs-function">() =&gt;</span> {
      context.value = { <span class="hljs-attr">y</span>: translateY.value };
    })
    .onChange(<span class="hljs-function">(<span class="hljs-params">event</span>) =&gt;</span> {
      translateY.value = <span class="hljs-built_in">Math</span>.max(
        event.translationY + context.value.y,
        <span class="hljs-number">-300</span>
      );
    })
    .onEnd(<span class="hljs-function">(<span class="hljs-params">event</span>) =&gt;</span> {
      <span class="hljs-keyword">if</span> (event.velocityY &gt; <span class="hljs-number">500</span>) {
        translateY.value = withSpring(<span class="hljs-number">300</span>); <span class="hljs-comment">// Dismiss</span>
      } <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (translateY.value &gt; <span class="hljs-number">-100</span>) {
        translateY.value = withSpring(<span class="hljs-number">-50</span>); <span class="hljs-comment">// Collapsed</span>
      } <span class="hljs-keyword">else</span> {
        translateY.value = withSpring(<span class="hljs-number">-300</span>); <span class="hljs-comment">// Expanded</span>
      }
    });

  <span class="hljs-keyword">const</span> animatedStyle = useAnimatedStyle(<span class="hljs-function">() =&gt;</span> ({
    <span class="hljs-attr">transform</span>: [{ <span class="hljs-attr">translateY</span>: translateY.value }],
  }));

  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">GestureDetector</span> <span class="hljs-attr">gesture</span>=<span class="hljs-string">{pan}</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">Animated.View</span> <span class="hljs-attr">style</span>=<span class="hljs-string">{[styles.bottomSheet,</span> <span class="hljs-attr">animatedStyle</span>]}&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">View</span> <span class="hljs-attr">style</span>=<span class="hljs-string">{styles.handle}</span> /&gt;</span>
        {children}
      <span class="hljs-tag">&lt;/<span class="hljs-name">Animated.View</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">GestureDetector</span>&gt;</span></span>
  );
}
</code></pre>
<p>The bottom sheet starts off-screen at translateY = 300. When you start dragging, <code>.onStart()</code> saves the starting position in <code>context</code>. As you drag, <code>.onChange()</code> updates the position, but <code>Math.max()</code> prevents it from going below -300 (fully expanded). When you release, <code>.onEnd()</code> checks the velocity – if you swiped down quickly (velocity &gt; 500), it dismisses. Otherwise, it snaps to either the collapsed (-50) or expanded (-300) position based on where you released it.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1763051520805/dd09d10f-4d77-40a9-be9c-ef85d69be69e.gif" alt="Bottom sheet demo" class="image--center mx-auto" width="600" height="400" loading="lazy"></p>
<h3 id="heading-swipe-to-delete">Swipe to Delete</h3>
<p>Swipe-to-delete lets users remove items from a list by swiping left. It's a common pattern in email apps and to-do lists. This uses worklets for gesture tracking and timing functions for the deletion animation.</p>
<pre><code class="lang-javascript"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">SwipeToDelete</span>(<span class="hljs-params">{ children, onDelete }</span>) </span>{
  <span class="hljs-keyword">const</span> translateX = useSharedValue(<span class="hljs-number">0</span>);
  <span class="hljs-keyword">const</span> itemHeight = useSharedValue(<span class="hljs-number">60</span>);

  <span class="hljs-keyword">const</span> pan = Gesture.Pan()
    .activeOffsetX([<span class="hljs-number">-10</span>, <span class="hljs-number">10</span>])
    .onChange(<span class="hljs-function">(<span class="hljs-params">event</span>) =&gt;</span> {
      <span class="hljs-keyword">if</span> (event.translationX &lt; <span class="hljs-number">0</span>) {
        translateX.value = event.translationX;
      }
    })
    .onEnd(<span class="hljs-function">() =&gt;</span> {
      <span class="hljs-keyword">if</span> (translateX.value &lt; <span class="hljs-number">-100</span>) {
        translateX.value = withTiming(<span class="hljs-number">-500</span>, { <span class="hljs-attr">duration</span>: <span class="hljs-number">200</span> });
        itemHeight.value = withTiming(<span class="hljs-number">0</span>, { <span class="hljs-attr">duration</span>: <span class="hljs-number">200</span> }, <span class="hljs-function">() =&gt;</span> {
          runOnJS(onDelete)();
        });
      } <span class="hljs-keyword">else</span> {
        translateX.value = withSpring(<span class="hljs-number">0</span>);
      }
    });

  <span class="hljs-keyword">const</span> animatedStyle = useAnimatedStyle(<span class="hljs-function">() =&gt;</span> ({
    <span class="hljs-attr">transform</span>: [{ <span class="hljs-attr">translateX</span>: translateX.value }],
    <span class="hljs-attr">height</span>: itemHeight.value,
  }));

  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">GestureDetector</span> <span class="hljs-attr">gesture</span>=<span class="hljs-string">{pan}</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">Animated.View</span> <span class="hljs-attr">style</span>=<span class="hljs-string">{[styles.item,</span> <span class="hljs-attr">animatedStyle</span>]}&gt;</span>
        {children}
      <span class="hljs-tag">&lt;/<span class="hljs-name">Animated.View</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">GestureDetector</span>&gt;</span></span>
  );
}
</code></pre>
<p>The <code>.activeOffsetX([-10, 10])</code> setting means the gesture only activates after you've moved 10 pixels horizontally, preventing accidental triggers during vertical scrolling. The <code>if (event.translationX &lt; 0)</code> check ensures you can only swipe left, not right. If you swipe past -100 pixels and release, it triggers the deletion: the item slides off-screen (-500), the height collapses to 0, and <code>runOnJS</code> calls your delete function from the UI thread back to JavaScript.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1763051815614/6e2c2d60-3d2e-49ec-9fb5-c17db00e9120.gif" alt="6e2c2d60-3d2e-49ec-9fb5-c17db00e9120" class="image--center mx-auto" width="600" height="400" loading="lazy"></p>
<p>These patterns demonstrate the power of combining Reanimated's animation approaches with gesture handling. Now, let's look at how to keep these animations performing smoothly.</p>
<h2 id="heading-performance-optimizations">Performance Optimizations</h2>
<p>Even though Reanimated runs on the UI thread, poorly structured animations can still drop frames. Here are four key optimizations that will keep your animations consistently smooth at 60 FPS.</p>
<h3 id="heading-memoize-animations">Memoize Animations</h3>
<p>Every time your component re-renders, any animations you create inside the render function are recreated. This wastes memory and processing time.</p>
<p>Don't do this – creating a new animation object on every render:</p>
<pre><code class="lang-javascript">{items.map(<span class="hljs-function"><span class="hljs-params">item</span> =&gt;</span> (
  <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">Animated.View</span> <span class="hljs-attr">entering</span>=<span class="hljs-string">{FadeIn.duration(300)}</span> <span class="hljs-attr">key</span>=<span class="hljs-string">{item.id}</span> /&gt;</span></span>
))}
</code></pre>
<p>Instead, create the animation once outside the component or memoize it:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> fadeIn = FadeIn.duration(<span class="hljs-number">300</span>);
{items.map(<span class="hljs-function"><span class="hljs-params">item</span> =&gt;</span> (
  <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">Animated.View</span> <span class="hljs-attr">entering</span>=<span class="hljs-string">{fadeIn}</span> <span class="hljs-attr">key</span>=<span class="hljs-string">{item.id}</span> /&gt;</span></span>
))}
</code></pre>
<p>By storing the animation in a constant, you create it once and reuse the same object for all items. This reduces memory allocation and garbage collection, keeping your animations smooth even with long lists.</p>
<h3 id="heading-use-usederivedvalue">Use useDerivedValue</h3>
<p>If you're doing expensive calculations inside <code>useAnimatedStyle</code>, those calculations run every frame, even if the dependencies haven't changed.</p>
<p>Don't do this – recalculating every frame:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> animatedStyle = useAnimatedStyle(<span class="hljs-function">() =&gt;</span> ({
  <span class="hljs-attr">width</span>: <span class="hljs-built_in">Math</span>.min(<span class="hljs-built_in">Math</span>.max(offset.value * <span class="hljs-number">2</span>, <span class="hljs-number">100</span>), <span class="hljs-number">500</span>),
}));
</code></pre>
<p>Instead, use <code>useDerivedValue</code> to compute the value only when dependencies change:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> width = useDerivedValue(<span class="hljs-function">() =&gt;</span> 
  <span class="hljs-built_in">Math</span>.min(<span class="hljs-built_in">Math</span>.max(offset.value * <span class="hljs-number">2</span>, <span class="hljs-number">100</span>), <span class="hljs-number">500</span>)
);

<span class="hljs-keyword">const</span> animatedStyle = useAnimatedStyle(<span class="hljs-function">() =&gt;</span> ({
  <span class="hljs-attr">width</span>: width.value,
}));
</code></pre>
<p>Now the complex calculation only runs when <code>offset.value</code> changes, not on every frame. The <code>useAnimatedStyle</code> just reads the pre-computed width, which is much faster.</p>
<h3 id="heading-batch-updates">Batch Updates</h3>
<p>When you update multiple shared values, each update can trigger a separate re-render. This creates unnecessary work for the UI thread.</p>
<p>Don't do this – triggering multiple re-renders:</p>
<pre><code class="lang-javascript">scale.value = withSpring(<span class="hljs-number">1.2</span>);
opacity.value = withSpring(<span class="hljs-number">0.8</span>);
</code></pre>
<p>Instead, batch the updates using <code>runOnUI</code>:</p>
<pre><code class="lang-javascript">runOnUI(<span class="hljs-function">() =&gt;</span> {
  <span class="hljs-string">'worklet'</span>;
  scale.value = withSpring(<span class="hljs-number">1.2</span>);
  opacity.value = withSpring(<span class="hljs-number">0.8</span>);
})();
</code></pre>
<p>The <code>runOnUI</code> function ensures both updates happen in the same frame, so the UI only re-renders once. This is especially important when updating many values at once, like in complex gestures or choreographed animations.</p>
<h3 id="heading-prefer-transform-over-layout">Prefer Transform Over Layout</h3>
<p>Animating layout properties like width, height, or margins forces React Native to recalculate the position of every element that depends on the changing element. This is expensive.</p>
<p>Don't do this – expensive layout recalculation:</p>
<pre><code class="lang-javascript">width: withSpring(newWidth)
</code></pre>
<p>Instead, use transform properties, which only affect the visual appearance without triggering layout:</p>
<pre><code class="lang-javascript">transform: [{ <span class="hljs-attr">scaleX</span>: withSpring(scale) }]
</code></pre>
<p>Transform operations are hardware-accelerated and don't affect layout, making them dramatically faster. Whenever possible, use <code>translateX/Y</code> instead of changing position, <code>scale</code> instead of changing size, and <code>rotate</code> instead of changing orientation.</p>
<p>These optimizations will keep your animations buttery smooth. Now let's look at how to debug issues when they arise.</p>
<h2 id="heading-debugging-tips">Debugging Tips</h2>
<p>Even with proper setup, you may encounter issues with animations. Here are the most common problems and their solutions, written as complete troubleshooting steps.</p>
<h3 id="heading-animations-not-working">Animations Not Working</h3>
<p>If your animations aren't running at all, the most common cause is a missing or incorrectly configured Babel plugin. Open your <code>babel.config.js</code> file and verify that <code>react-native-worklets/plugin</code> is present in the plugins array and is the last plugin in the list. The order matters because the worklets plugin needs to process your code after all other transformations.</p>
<p>After confirming the plugin is correctly configured, clear your Metro bundler cache by running <code>npm start -- --reset-cache</code>, then rebuild your app completely. Simply reloading JavaScript won't work because Babel transformations happen during the build process.</p>
<h3 id="heading-app-crashes-on-startup-or-reload">App Crashes on Startup or Reload</h3>
<p>If your app crashes immediately after installing Reanimated or when you reload, the native modules likely aren't properly linked. With React Native 0.76+, this usually means the pods weren't installed or the native build is out of sync.</p>
<p>For iOS, run <code>cd ios &amp;&amp; pod install &amp;&amp; cd ..</code> then do a clean build with <code>npx react-native run-ios</code>. For Android, clean the build with <code>cd android &amp;&amp; ./gradlew clean &amp;&amp; cd ..</code> then rebuild with <code>npx react-native run-android</code>.</p>
<p>If you're getting build errors about missing headers or modules, make sure you've added both <code>react-native-reanimated</code> and <code>react-native-worklets</code> to your package.json dependencies.</p>
<h3 id="heading-turbomoduleregistry-not-found">"TurboModuleRegistry Not Found"</h3>
<p>If you see an error message saying "TurboModuleRegistry.get('NativeReanimated'): 'NativeReanimated' could not be found", it means the native code hasn't been properly linked to your JavaScript code.</p>
<p>First, verify you're using React Native 0.76 or newer, as Reanimated 4 requires the New Architecture. Check your <code>ios/Podfile</code> for <code>ENV['RCT_NEW_ARCH_ENABLED'] = '1'</code> and <code>android/gradle.properties</code> for <code>newArchEnabled=true</code>.</p>
<p>Then rebuild completely: <code>cd ios &amp;&amp; pod install &amp;&amp; cd .. &amp;&amp; npx react-native run-ios</code>.</p>
<h3 id="heading-logging-and-inspecting-shared-values">Logging and Inspecting Shared Values</h3>
<p>If you try to debug worklets using <code>console.log()</code>, you'll notice nothing appears in your console. This is because worklets run on the UI thread, which doesn't have direct access to the JavaScript console.</p>
<p>To log values from worklets, use the <code>useDerivedValue</code> hook:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> offset = useSharedValue(<span class="hljs-number">0</span>);

useDerivedValue(<span class="hljs-function">() =&gt;</span> {
  <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'Offset:'</span>, offset.value);
  <span class="hljs-keyword">return</span> offset.value;
});
</code></pre>
<p>For more advanced debugging, React Native's built-in debugger (accessed through dev menu → "Open Debugger") now supports debugging both threads. You can set breakpoints in worklets and inspect shared values in real-time.</p>
<h3 id="heading-monitor-performance">Monitor Performance</h3>
<p>To see if your animations are actually running at 60 FPS, enable the Performance Monitor built into React Native. Shake your device (or press Cmd+D in the iOS simulator, Cmd+M in Android emulator) to open the dev menu, then select "Show Perf Monitor".</p>
<p>The monitor displays two critical numbers: JS thread FPS and UI thread FPS. Your animations run on the UI thread, so watch that number. If it stays at 60 FPS, your animations are smooth. If it drops below 60, your animations are skipping frames and will appear janky. The JS thread FPS shows whether your React code is keeping up – if this drops, it indicates issues with your component renders, not your animations.</p>
<p>For more detailed debugging information and advanced troubleshooting, check the <a target="_blank" href="https://docs.swmansion.com/react-native-reanimated/docs/guides/debugging/">official debugging guide here</a>.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1763053624344/7aeffb5f-4829-4871-bd49-6e589adeb8ad.png" alt="7aeffb5f-4829-4871-bd49-6e589adeb8ad" class="image--center mx-auto" width="600" height="400" loading="lazy"></p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>Reanimated 4 gives you two powerful approaches to animation: CSS animations for simple state changes and worklets for complex, interactive animations that need real-time control.</p>
<p>Start with CSS transitions when building your next animation feature. They're simpler to write, easier to maintain, and perfect for the majority of UI animations. Reach for worklets when you need gesture control, scroll effects, or any animation that requires frame-by-frame updates.</p>
<p>The <a target="_blank" href="https://docs.swmansion.com/react-native-reanimated">official documentation</a> provides complete API references, detailed guides, and interactive examples. The <a target="_blank" href="https://github.com/software-mansion/react-native-reanimated">GitHub repository</a> includes production-ready sample code you can study and adapt.</p>
<p>Building smooth animations isn't just about technical capability – it's about creating experiences that feel responsive, intuitive, and delightful to use. Reanimated 4 makes achieving that standard straightforward, whether you're animating a simple button press or building a complex screen transition with multiple coordinated elements.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Use Animations in Flutter ]]>
                </title>
                <description>
                    <![CDATA[ Animations are a fundamental aspect of mobile app development. They go beyond just adding visual appeal, and have become essential for enhancing the overall user experience. Flutter, Google's open-source UI development toolkit, lets you create seamle... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-use-animations-in-flutter/</link>
                <guid isPermaLink="false">68e0186a13e5a2b425ebad2e</guid>
                
                    <category>
                        <![CDATA[ Flutter ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Dart ]]>
                    </category>
                
                    <category>
                        <![CDATA[ flutter-aware ]]>
                    </category>
                
                    <category>
                        <![CDATA[ animation ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Atuoha Anthony ]]>
                </dc:creator>
                <pubDate>Fri, 03 Oct 2025 18:39:38 +0000</pubDate>
                <media:content url="https://cdn.hashnode.com/res/hashnode/image/upload/v1759507962194/9f1bff80-2205-4e63-a6b7-8fee605bc5fa.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Animations are a fundamental aspect of mobile app development. They go beyond just adding visual appeal, and have become essential for enhancing the overall user experience.</p>
<p>Flutter, Google's open-source UI development toolkit, lets you create seamless and engaging animations effortlessly. Let's delve deeper into why animations are crucial and how Flutter makes animation development an exciting and creative endeavor.</p>
<h2 id="heading-table-of-contents">Table of Contents:</h2>
<ol>
<li><p><a class="post-section-overview" href="#heading-prerequisites">Prerequisites</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-quick-setup-commands">Quick setup commands</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-why-animations-matter">Why animations matter</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-high-level-types-of-flutter-animations">High-level types of Flutter animations</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-implicit-animations">Implicit animations</a></p>
<ul>
<li><a class="post-section-overview" href="#heading-animatedcontainer-example">AnimatedContainer example</a></li>
</ul>
</li>
<li><p><a class="post-section-overview" href="#heading-explicit-animations">Explicit animations</a></p>
<ul>
<li><a class="post-section-overview" href="#heading-explanation">Explanation</a></li>
</ul>
</li>
<li><p><a class="post-section-overview" href="#heading-curved-animations">Curved animations</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-chaining-animations-translation-rotation">Chaining animations (translation + rotation)</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-staggered-animations">Staggered animations</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-hero-animations">Hero animations</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-animatedbuilder-with-multiple-properties">AnimatedBuilder with multiple properties</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-gesture-based-animations">Gesture-based animations</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-animatedswitcher">AnimatedSwitcher</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-tweensequence">TweenSequence</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-physics-based-animations">Physics-based animations</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-tweensequence-vs-staggered-vs-chained">TweenSequence vs Staggered vs Chained</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-animatedwidget-vs-animatedbuilder">AnimatedWidget vs AnimatedBuilder</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-extra-practical-tips-and-best-practices">Extra practical tips and best practices</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-common-helpers-amp-widgets-cheat-list">Common helpers &amp; widgets (cheat-list)</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-references">References</a></p>
</li>
</ol>
<h2 id="heading-prerequisites">Prerequisites</h2>
<p>Before diving into Flutter animations, make sure your development environment is ready. You should have:</p>
<ul>
<li><p><strong>Flutter SDK installed and added to PATH</strong>. You can confirm this by running <code>flutter doctor</code>, which checks your setup for common issues and ensures everything needed for Flutter development is properly installed.</p>
</li>
<li><p><strong>Basic knowledge of Dart and Flutter widgets</strong>, including <code>StatelessWidget</code>, <code>StatefulWidget</code>, and understanding the <code>build()</code> method.</p>
</li>
<li><p><strong>An IDE</strong> like VS Code or Android Studio, with Flutter plugins installed.</p>
</li>
<li><p><strong>A device or emulator</strong> available to run your projects using <code>flutter run</code>.</p>
</li>
<li><p><strong>Familiarity with async/await</strong> and Dart null-safety (<code>late</code>, non-nullable types).</p>
</li>
</ul>
<h2 id="heading-quick-setup-commands">Quick Setup Commands</h2>
<p>For this guide, we’ll use a simple demo project called <code>animation_demo</code> to explore various animations. Here’s how to get started:</p>
<pre><code class="lang-bash">flutter doctor
flutter create animation_demo
<span class="hljs-built_in">cd</span> animation_demo
flutter run
</code></pre>
<ul>
<li><p><code>flutter doctor</code>: checks your environment and tells you if anything is missing.</p>
</li>
<li><p><code>flutter create animation_demo</code>: scaffolds a new Flutter project called <code>animation_demo</code>.</p>
</li>
<li><p><code>flutter run</code>: launches the app on a connected device or emulator.</p>
</li>
</ul>
<p>With this setup, we can start experimenting with animations.</p>
<h2 id="heading-why-animations-matter">Why Animations Matter</h2>
<p>Animations are not just about making an app look fancy. They also play a crucial role in improving user experience. Thoughtful animations help users understand your interface, provide feedback, and make your app feel smoother and more engaging.</p>
<p>For example, visual feedback is essential when a user interacts with your app. A button press might slightly scale down or produce a ripple effect to indicate that the action has been recognized. Smooth transitions also help users understand navigation or changes in the interface. Moving from a list view to a detail view using a hero animation feels intuitive rather than abrupt or jarring.</p>
<p>Finally, well-designed animations can increase engagement and perceived performance. Subtle movements, transitions, or loading indicators can make an app feel faster and more responsive. When animations are thoughtfully implemented, they elevate the overall quality of the application, making it feel polished and professional.</p>
<h2 id="heading-high-level-types-of-flutter-animations">High-Level Types of Flutter Animations</h2>
<p>Flutter offers a variety of animation types to handle different scenarios. Understanding these types conceptually is important before jumping into the code:</p>
<h3 id="heading-implicit-animations">Implicit Animations</h3>
<p>These are simple, property-based animations that require minimal setup. For example, animating a container’s width, height, or color can be done with widgets like <code>AnimatedContainer</code>, <code>AnimatedOpacity</code>, or <code>AnimatedPositioned</code>. Implicit animations are ideal for straightforward changes without needing fine-grained control.</p>
<h3 id="heading-explicit-animations">Explicit Animations</h3>
<p>Explicit animations give you full control over timing, easing, and the animation lifecycle. You use <code>AnimationController</code>, <code>Tween</code>, and widgets like <code>AnimatedBuilder</code> or <code>AnimatedWidget</code> to create custom, complex animations. Explicit animations are best when you need precise control over multiple properties or custom behavior.</p>
<h3 id="heading-physics-based-animations">Physics-based Animations</h3>
<p>Physics-based animations simulate natural motion using Flutter’s <code>flutter/physics</code> library. Examples include <code>SpringSimulation</code> and <code>FlingSimulation</code>. These are perfect when you want realistic, natural-feeling motion, such as draggable widgets or bouncy UI elements.</p>
<h3 id="heading-hero-animations">Hero Animations</h3>
<p>Hero animations enable shared element transitions between screens. Using the <code>Hero</code> widget, you can animate a widget from one route to another, making transitions feel fluid and connected.</p>
<h3 id="heading-staggered-amp-sequence-animations">Staggered &amp; Sequence Animations</h3>
<p>Staggered animations let you time multiple animations to start at different moments. <code>TweenSequence</code> allows multi-stage, chained animations within a single controller. These techniques are useful for orchestrating complex UI movements.</p>
<p>Let’s now go through each of these types of animations so you can see how they work in practice.</p>
<h2 id="heading-implicit-animations-1">Implicit Animations</h2>
<p>Implicit animations let you animate widget property changes automatically. Let’s see an example with <code>AnimatedContainer</code>:</p>
<pre><code class="lang-dart">AnimatedContainer(
  duration: <span class="hljs-built_in">Duration</span>(milliseconds: <span class="hljs-number">300</span>),
  width: _isExpanded ? <span class="hljs-number">200</span> : <span class="hljs-number">100</span>,
  height: _isExpanded ? <span class="hljs-number">200</span> : <span class="hljs-number">100</span>,
  color: _isExpanded ? Colors.blue : Colors.grey,
  curve: Curves.easeInOut,
  child: Center(child: Text(<span class="hljs-string">'Tap'</span>)),
)
</code></pre>
<p>Here’s what’s going on in this code:</p>
<ul>
<li><p><code>AnimatedContainer</code>: automatically animates changes to its properties.</p>
</li>
<li><p><code>duration</code>: sets how long the animation takes.</p>
</li>
<li><p><code>width</code> / <code>height</code>: animates between 100 and 200 depending on <code>_isExpanded</code>.</p>
</li>
<li><p><code>color</code>: animates from grey to blue.</p>
</li>
<li><p><code>curve</code>: controls acceleration/deceleration, making movement feel natural.</p>
</li>
<li><p><code>child</code>: optional child widget, which is not animated unless its own properties change.</p>
</li>
</ul>
<p>Implicit animations are perfect for quick, property-based effects with minimal code.</p>
<h2 id="heading-explicit-animations-1">Explicit Animations</h2>
<p>Explicit animations require more setup but give full control. Here’s a complete, modern, null-safe example that scales a button:</p>
<pre><code class="lang-dart"><span class="hljs-keyword">import</span> <span class="hljs-string">'package:flutter/material.dart'</span>;

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">ScaleDemo</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">StatefulWidget</span> </span>{
  <span class="hljs-meta">@override</span>
  _ScaleDemoState createState() =&gt; _ScaleDemoState();
}

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">_ScaleDemoState</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">State</span>&lt;<span class="hljs-title">ScaleDemo</span>&gt; <span class="hljs-title">with</span> <span class="hljs-title">SingleTickerProviderStateMixin</span> </span>{
  <span class="hljs-keyword">late</span> <span class="hljs-keyword">final</span> AnimationController _controller;
  <span class="hljs-keyword">late</span> <span class="hljs-keyword">final</span> Animation&lt;<span class="hljs-built_in">double</span>&gt; _animation;

  <span class="hljs-meta">@override</span>
  <span class="hljs-keyword">void</span> initState() {
    <span class="hljs-keyword">super</span>.initState();
    _controller = AnimationController(
      duration: <span class="hljs-keyword">const</span> <span class="hljs-built_in">Duration</span>(seconds: <span class="hljs-number">1</span>),
      vsync: <span class="hljs-keyword">this</span>,
    );
    _animation = Tween&lt;<span class="hljs-built_in">double</span>&gt;(begin: <span class="hljs-number">0.5</span>, end: <span class="hljs-number">1.5</span>).animate(_controller);
  }

  <span class="hljs-meta">@override</span>
  Widget build(BuildContext context) {
    <span class="hljs-keyword">return</span> Scaffold(
      appBar: AppBar(title: <span class="hljs-keyword">const</span> Text(<span class="hljs-string">'Scale Animation'</span>)),
      body: Center(
        child: AnimatedBuilder(
          animation: _animation,
          builder: (context, child) {
            <span class="hljs-keyword">return</span> Transform.scale(
              scale: _animation.value,
              child: child,
            );
          },
          child: ElevatedButton(
            onPressed: () {
              <span class="hljs-keyword">if</span> (_controller.status == AnimationStatus.completed) {
                _controller.reverse();
              } <span class="hljs-keyword">else</span> {
                _controller.forward();
              }
            },
            child: <span class="hljs-keyword">const</span> Text(<span class="hljs-string">'Animate'</span>),
          ),
        ),
      ),
    );
  }

  <span class="hljs-meta">@override</span>
  <span class="hljs-keyword">void</span> dispose() {
    _controller.dispose();
    <span class="hljs-keyword">super</span>.dispose();
  }
}
</code></pre>
<p>Let’s look at the key concepts from this code:</p>
<ul>
<li><p><strong>AnimationController</strong>: controls the animation timeline from 0.0 to 1.0.</p>
</li>
<li><p><strong>Tween</strong>: maps the controller values to a range (here, 0.5 → 1.5 for scaling). A tween defines the start and end values of an animation.</p>
</li>
<li><p><strong>AnimatedBuilder</strong>: rebuilds only the widgets inside its builder during animation ticks, optimizing performance.</p>
</li>
<li><p><strong>Child parameter in AnimatedBuilder</strong>: avoids rebuilding expensive widgets each frame. In this example, the button is passed as <code>child</code> to prevent unnecessary rebuilds.</p>
</li>
</ul>
<p>You can also use a simpler <code>TextButton</code> with the same animation logic:</p>
<pre><code class="lang-dart">TextButton(
  onPressed: () {
    <span class="hljs-keyword">if</span> (_controller.status == AnimationStatus.completed) {
      _controller.reverse();
    } <span class="hljs-keyword">else</span> {
      _controller.forward();
    }
  },
  child: Text(<span class="hljs-string">'Animate'</span>),
)
</code></pre>
<h2 id="heading-curved-animations">Curved Animations</h2>
<p>Animations often feel unnatural if they move linearly. <strong>CurvedAnimation</strong> modifies the progression of the animation to make it more natural:</p>
<pre><code class="lang-dart">_controller = AnimationController(
  duration: <span class="hljs-built_in">Duration</span>(seconds: <span class="hljs-number">2</span>),
  vsync: <span class="hljs-keyword">this</span>,
);
_animation = CurvedAnimation(
  parent: _controller,
  curve: Curves.easeInOut,
);
</code></pre>
<p><strong>CurvedAnimation</strong> wraps a controller and applies a curve to remap 0→1 linearly into eased values.</p>
<p>Often, you combine a CurvedAnimation with a Tween like this:</p>
<pre><code class="lang-dart">_animation = Tween&lt;<span class="hljs-built_in">double</span>&gt;(begin: <span class="hljs-number">0</span>, end: <span class="hljs-number">1</span>).animate(
  CurvedAnimation(parent: _controller, curve: Curves.easeInOut),
);
</code></pre>
<p><strong>Tween</strong> here defines the start and end value of an animation, providing the numeric range that the controller drives.</p>
<h2 id="heading-chaining-animations-translation-rotation">Chaining Animations (Translation + Rotation)</h2>
<p>Sometimes, you want a widget to move and rotate simultaneously. Here’s how to set up such animations:</p>
<pre><code class="lang-dart"><span class="hljs-keyword">import</span> <span class="hljs-string">'dart:math'</span> <span class="hljs-keyword">as</span> math;

_translation = Tween&lt;<span class="hljs-built_in">double</span>&gt;(begin: <span class="hljs-number">0</span>, end: <span class="hljs-number">100</span>).animate(_controller);
_rotation = Tween&lt;<span class="hljs-built_in">double</span>&gt;(begin: <span class="hljs-number">0</span>, end: <span class="hljs-number">2</span> * math.pi).animate(_controller);
</code></pre>
<p>This is what’s going on here:</p>
<ul>
<li><p><code>math.pi</code> is used for rotation calculations.</p>
</li>
<li><p><code>_translation</code> moves the widget 100 pixels horizontally.</p>
</li>
<li><p><code>_rotation</code> rotates the widget 360 degrees (2π radians).</p>
</li>
</ul>
<p>You can wrap both in a nested <code>Transform</code> inside <code>AnimatedBuilder</code> like this:</p>
<pre><code class="lang-dart">Transform.translate(
  offset: Offset(_translation.value, <span class="hljs-number">0</span>),
  child: Transform.rotate(angle: _rotation.value, child: YourWidget()),
);
</code></pre>
<h2 id="heading-staggered-animations">Staggered Animations</h2>
<p>Staggering allows multiple animations to run at different intervals on the same controller:</p>
<pre><code class="lang-dart">_controller = AnimationController(duration: <span class="hljs-built_in">Duration</span>(seconds: <span class="hljs-number">2</span>), vsync: <span class="hljs-keyword">this</span>);

_animation1 = Tween&lt;<span class="hljs-built_in">double</span>&gt;(begin: <span class="hljs-number">0</span>, end: <span class="hljs-number">1</span>).animate(
  CurvedAnimation(
    parent: _controller,
    curve: Interval(<span class="hljs-number">0.0</span>, <span class="hljs-number">0.5</span>, curve: Curves.easeInOut),
  ),
);

_animation2 = Tween&lt;<span class="hljs-built_in">double</span>&gt;(begin: <span class="hljs-number">0</span>, end: <span class="hljs-number">1</span>).animate(
  CurvedAnimation(
    parent: _controller,
    curve: Interval(<span class="hljs-number">0.5</span>, <span class="hljs-number">1.0</span>, curve: Curves.easeInOut),
  ),
);
</code></pre>
<ul>
<li><p><strong>Interval</strong> defines when each animation starts and ends relative to the controller’s timeline.</p>
</li>
<li><p>Both animations share the same controller but run in sequence.</p>
</li>
</ul>
<h2 id="heading-hero-animations-1">Hero Animations</h2>
<p>Hero animations create smooth transitions between routes:</p>
<p><strong>First Screen:</strong></p>
<pre><code class="lang-dart"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">FirstScreen</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">StatelessWidget</span> </span>{
  <span class="hljs-meta">@override</span>
  Widget build(BuildContext context) {
    <span class="hljs-keyword">return</span> GestureDetector(
      onTap: () {
        Navigator.push(context, MaterialPageRoute(builder: (context) =&gt; SecondScreen()));
      },
      child: Hero(
        tag: <span class="hljs-string">'hero-tag'</span>,
        child: Image.asset(<span class="hljs-string">'assets/avatar.png'</span>, width: <span class="hljs-number">100</span>, height: <span class="hljs-number">100</span>),
      ),
    );
  }
}
</code></pre>
<p><strong>Second Screen:</strong></p>
<pre><code class="lang-dart"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">SecondScreen</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">StatelessWidget</span> </span>{
  <span class="hljs-meta">@override</span>
  Widget build(BuildContext context) {
    <span class="hljs-keyword">return</span> Scaffold(
      body: Center(
        child: Hero(
          tag: <span class="hljs-string">'hero-tag'</span>,
          child: Image.asset(<span class="hljs-string">'assets/avatar.png'</span>, width: <span class="hljs-number">300</span>, height: <span class="hljs-number">300</span>),
        ),
      ),
    );
  }
}
</code></pre>
<ul>
<li><p><strong>Hero widget</strong> animates the shared element between routes.</p>
</li>
<li><p><strong>Tag</strong> must be unique for each shared animation.</p>
</li>
<li><p>Automatically interpolates size, position, and shape.</p>
</li>
</ul>
<h2 id="heading-animatedbuilder-with-multiple-properties">AnimatedBuilder with Multiple Properties</h2>
<p>You can animate several properties simultaneously:</p>
<pre><code class="lang-dart">_controller = AnimationController(duration: <span class="hljs-built_in">Duration</span>(seconds: <span class="hljs-number">2</span>), vsync: <span class="hljs-keyword">this</span>);

_width = Tween&lt;<span class="hljs-built_in">double</span>&gt;(begin: <span class="hljs-number">100</span>, end: <span class="hljs-number">200</span>).animate(_controller);
_height = Tween&lt;<span class="hljs-built_in">double</span>&gt;(begin: <span class="hljs-number">100</span>, end: <span class="hljs-number">200</span>).animate(_controller);

AnimatedBuilder(
  animation: _controller,
  builder: (context, child) {
    <span class="hljs-keyword">return</span> Container(
      width: _width.value,
      height: _height.value,
      child: child,
    );
  },
  child: YourWidget(),
)
</code></pre>
<ul>
<li><p>Multiple <code>Tween&lt;double&gt;</code> objects progress together with one controller.</p>
</li>
<li><p>Using <code>child</code> prevents unnecessary rebuilds of the widget subtree.</p>
</li>
</ul>
<h2 id="heading-gesture-based-animations">Gesture-based Animations</h2>
<p>Gesture-based animations respond to direct user interactions like taps, drags, swipes, or long presses. These are especially useful when building interactive UIs such as draggable cards, swipe-to-dismiss lists, or custom sliders.</p>
<p>In the example below, the animation listens for horizontal drag gestures (<code>onPanUpdate</code> and <code>onPanEnd</code>). As the user drags, the widget smoothly follows the finger. When the gesture ends, the animation decides whether to snap forward or reverse depending on how far the user has dragged.</p>
<pre><code class="lang-dart">_controller = AnimationController(duration: <span class="hljs-built_in">Duration</span>(milliseconds: <span class="hljs-number">300</span>), vsync: <span class="hljs-keyword">this</span>);
_position = Tween&lt;<span class="hljs-built_in">double</span>&gt;(begin: <span class="hljs-number">0</span>, end: <span class="hljs-number">200</span>).animate(_controller);

GestureDetector(
  onPanUpdate: (details) {
    _controller.value -= (details.primaryDelta ?? <span class="hljs-number">0</span>) / <span class="hljs-number">200</span>;
  },
  onPanEnd: (_) {
    <span class="hljs-keyword">if</span> (_controller.value &gt; <span class="hljs-number">0.5</span>) {
      _controller.forward();
    } <span class="hljs-keyword">else</span> {
      _controller.reverse();
    }
  },
  child: AnimatedBuilder(
    animation: _controller,
    builder: (context, child) {
      <span class="hljs-keyword">return</span> Transform.translate(offset: Offset(_position.value, <span class="hljs-number">0</span>), child: YourWidget());
    },
  ),
)
</code></pre>
<ul>
<li><p><code>onPanUpdate</code> maps gesture movement to controller progress.</p>
</li>
<li><p><code>onPanEnd</code> determines the final animation state.</p>
</li>
</ul>
<h2 id="heading-animatedswitcher">AnimatedSwitcher</h2>
<p><code>AnimatedSwitcher</code> is ideal when you want to swap between two widgets with a smooth transition, such as toggling between login and signup forms, or replacing a loading spinner with actual content. It automatically handles fading, scaling, or custom transitions when the child widget changes.</p>
<p>For example, you can switch between widgets with a crossfade animation:</p>
<pre><code class="lang-dart">AnimatedSwitcher(
  duration: <span class="hljs-built_in">Duration</span>(seconds: <span class="hljs-number">1</span>),
  child: _showFirstWidget ? YourFirstWidget() : YourSecondWidget(),
)
</code></pre>
<p><strong>Keys</strong> ensure AnimatedSwitcher recognizes different widgets:</p>
<pre><code class="lang-dart">AnimatedSwitcher(
  duration: <span class="hljs-built_in">Duration</span>(milliseconds: <span class="hljs-number">500</span>),
  child: _showFirstWidget
      ? Container(key: ValueKey(<span class="hljs-string">'first'</span>), child: YourFirstWidget())
      : Container(key: ValueKey(<span class="hljs-string">'second'</span>), child: YourSecondWidget()),
)
</code></pre>
<h2 id="heading-tweensequence">TweenSequence</h2>
<p>Use <code>TweenSequence</code> when you want an animation that passes through multiple stages in a single timeline, like pulsing a button (grow -&gt; shrink -&gt; reset) or animating a progress bar with different speeds at different phase</p>
<p>You can create multi-stage animations like this:</p>
<pre><code class="lang-dart">_controller = AnimationController(duration: <span class="hljs-built_in">Duration</span>(seconds: <span class="hljs-number">4</span>), vsync: <span class="hljs-keyword">this</span>);

_animation = TweenSequence&lt;<span class="hljs-built_in">double</span>&gt;([
  TweenSequenceItem(tween: Tween(begin: <span class="hljs-number">0.0</span>, end: <span class="hljs-number">1.0</span>), weight: <span class="hljs-number">1</span>),
  TweenSequenceItem(tween: Tween(begin: <span class="hljs-number">1.0</span>, end: <span class="hljs-number">0.0</span>), weight: <span class="hljs-number">1</span>),
]).animate(_controller);
</code></pre>
<ul>
<li><p>Each stage is defined by a <code>TweenSequenceItem</code>.</p>
</li>
<li><p>Weight determines relative duration.</p>
</li>
</ul>
<h2 id="heading-physics-based-animations-1">Physics-based Animations</h2>
<p>Physics-based animations are best for interactions that should feel “natural”, like bouncing, springing, flinging, or decelerating motion. For example, you can use them for draggable sheets, swipe-to-dismiss cards, or elastic overscroll effects. Unlike fixed-duration animations, they rely on parameters like mass, stiffness, and damping to simulate real-world physics.</p>
<p>If you want to simulate realistic motion, this is how you can do it:</p>
<pre><code class="lang-dart"><span class="hljs-keyword">import</span> <span class="hljs-string">'package:flutter/physics.dart'</span>;

<span class="hljs-keyword">final</span> SpringDescription spring = SpringDescription(mass: <span class="hljs-number">1</span>, stiffness: <span class="hljs-number">100</span>, damping: <span class="hljs-number">10</span>);
<span class="hljs-keyword">final</span> SpringSimulation sim = SpringSimulation(spring, <span class="hljs-number">0.0</span>, <span class="hljs-number">1.0</span>, <span class="hljs-number">0.0</span>);
_controller.animateWith(sim);
</code></pre>
<p>SpringSimulation drives the animation according to physics parameters.</p>
<h2 id="heading-tips-best-practices-amp-cheat-sheet">Tips, Best Practices &amp; Cheat Sheet</h2>
<ul>
<li><p>Use vsync with TickerProvider mixins to reduce CPU and battery usage. For example, <code>SingleTickerProviderStateMixin</code> ensures the animation only ticks when the screen is visible, reducing wasted CPU cycles and saving battery.</p>
</li>
<li><p>Always dispose controllers in <code>dispose()</code>. Failing to dispose <code>AnimationController</code> can cause memory leaks. Always call <code>_controller.dispose()</code> in your <code>State</code> class.</p>
</li>
<li><p>Prefer const constructors where possible for better rebuild performance. Using <code>const</code> for static widgets like icons or text prevents them from rebuilding unnecessarily.</p>
</li>
<li><p>Wrap only the portion that needs animation and minimize rebuild areas. Don’t wrap your entire screen in <code>AnimatedBuilder</code>. Instead, isolate just the widget that changes (for example, a single button scaling).</p>
</li>
<li><p>Profile using Flutter DevTools if frames drop below 60fps: If you notice dropped frames, open the Performance tab in DevTools to identify expensive rebuilds or heavy animations.</p>
</li>
<li><p>Keep animations subtle, as overuse can harm UX. For example, a button scaling from 1.0 to 1.05 feels natural. Scaling to 1.5 might feel jarring unless it’s intentional.</p>
</li>
<li><p>Test animations on real devices. Simulators often run animations smoothly. Test on mid-range Android phones to ensure performance is acceptable.</p>
</li>
</ul>
<p><strong>Common helpers and widgets:</strong></p>
<ul>
<li><p><strong>Implicit</strong>: <code>AnimatedContainer</code>, <code>AnimatedOpacity</code>, <code>AnimatedPositioned</code>, <code>AnimatedCrossFade</code>, <code>AnimatedSwitcher</code>. This is best for quick, one-line property changes.</p>
</li>
<li><p><strong>Explicit utilities</strong>: <code>AnimationController</code>, <code>Tween</code>, <code>CurvedAnimation</code>, <code>AnimatedBuilder</code>, <code>AnimatedWidget</code>. Use these when you need precision and lifecycle control.</p>
</li>
<li><p><strong>Physics</strong>: <code>SpringSimulation</code>, <code>FlingSimulation</code>, <code>ClampingScrollSimulation</code>. This is great for natural drag and bounce effects.</p>
</li>
<li><p><strong>Transitions</strong>: <code>Hero</code>, <code>PageRouteBuilder</code>. This is best for cross-screen navigation and shared elements.</p>
</li>
<li><p><strong>Gesture-driven</strong>: <code>GestureDetector</code>, <code>Draggable</code>, <code>Dismissible</code>. Use these when you want direct interaction like dragging or swiping.</p>
</li>
</ul>
<h2 id="heading-conclusion">Conclusion</h2>
<p>Animations in Flutter are more than just eye candy. They’re tools for guiding users, providing feedback, and making apps feel alive. From simple implicit animations to advanced physics-based interactions, Flutter gives you the flexibility to craft experiences that feel natural and engaging.</p>
<p>As you experiment, start small with implicit animations, then move into explicit and gesture-driven techniques for more control. Always keep performance and user experience in mind: subtle, purposeful animations go a long way toward making your app feel polished.</p>
<p>With these building blocks and best practices, you’re ready to bring your Flutter UIs to life.</p>
<p><strong>References:</strong></p>
<ul>
<li><p><a target="_blank" href="https://docs.flutter.dev/cookbook/animation">Flutter cookbook: animations</a></p>
</li>
<li><p><a target="_blank" href="https://docs.flutter.dev/tools/devtools/performance">Animation performance &amp; best practices (DevTools)</a></p>
</li>
<li><p>Books: <em>Flutter in Action</em> (Eric Windmill), <em>Practical Flutter</em> (Frank Zammetti)</p>
</li>
</ul>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Create an Animated Hamburger Menu in React ]]>
                </title>
                <description>
                    <![CDATA[ By Yazdun Fadali If you're looking to add some polished animations to your React apps, Framer Motion is the tool for the job.  In this tutorial, I'll walk you through creating a fully animated mobile menu using Framer Motion in React. What Are We Goi... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-create-an-animated-hamburger-menu-in-react/</link>
                <guid isPermaLink="false">66d46178d14641365a050989</guid>
                
                    <category>
                        <![CDATA[ animation ]]>
                    </category>
                
                    <category>
                        <![CDATA[ React ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ freeCodeCamp ]]>
                </dc:creator>
                <pubDate>Tue, 07 Nov 2023 17:15:20 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2023/11/Frame-14.jpg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>By Yazdun Fadali</p>
<p>If you're looking to add some polished animations to your React apps, Framer Motion is the tool for the job. </p>
<p>In this tutorial, I'll walk you through creating a fully animated mobile menu using Framer Motion in React.</p>
<h2 id="heading-what-are-we-going-to-build"><strong>What Are We Going to Build?</strong></h2>
<p>In this tutorial, I'll guide you step by step through implementing a complete animated and responsive mobile menu component in React using Framer Motion.</p>
<p>You can also checkout this in-depth <a target="_blank" href="https://youtu.be/FZRzwMjdwxk?si=QX-2tosWy1q3KwRI">video tutorial</a> I have created based on this article.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/11/ezgif-5-e28e07a84d.gif" alt="A screen recording which displays a fully animated mobile menu. On large screen devices, the routes will be displayed normally as an urdorder list, but in small screen devices, you will see a hamburger icon. Once you click on the hamburger icon, you will be able to see the animated mobile menu items" width="600" height="400" loading="lazy">
<em>Responsve navbar with a fully animated mobile menu</em></p>
<h2 id="heading-prerequisites">Prerequisites</h2>
<p>While prior familiarity with Framer Motion is not required to get started with this tutorial, it is important to have a foundation in React, as I won't cover basic React concepts in detail here.</p>
<p>Throughout this tutorial, you'll be utilizing the following tools:</p>
<ul>
<li><strong>React 18.2.0:</strong> React is a JavaScript library used for building user interfaces. It allows developers to create reusable UI components and efficiently update the UI based on data changes.</li>
<li><strong>Framer Motion:</strong> Framer Motion is a popular animation library for React. It provides an easy-to-use interface for creating smooth, interactive animations and transitions in web applications.</li>
<li><strong>Vite:</strong> Vite is a fast development server and build tool for modern web applications.</li>
<li><strong>Tailwind</strong>: You will be using Tailwind to apply styles to your React components in this tutorial.</li>
</ul>
<h2 id="heading-getting-started"><strong>Getting Started</strong></h2>
<p>To get started with this tutorial, I've prepared a boilerplate project for you which contains all the required dependencies, so you don't need to set up your project from scratch.</p>
<p>Simply clone the <a target="_blank" href="https://github.com/Yazdun/react-burger-menu/tree/starter">starter boilerplate</a> from the GitHub repository and then follow along with the tutorial.</p>
<ul>
<li>Starter Boilerplate: <a target="_blank" href="https://github.com/Yazdun/react-animated-sidebar/tree/starter">View on GitHub</a></li>
<li>Final Version: <a target="_blank" href="https://github.com/Yazdun/react-burger-menu/tree/main">View on GitHub</a></li>
</ul>
<h2 id="heading-how-to-create-a-simple-navbar-in-react">How to Create a Simple Navbar in React</h2>
<p>Before you start creating the animated mobile menu, it's important to first address the desktop navbar. You want to ensure that your navbar not only remains responsive but also looks good on desktop devices.</p>
<p>I've already set up a <code>routes</code> directory for you, containing an array with all the necessary routes for your app. You can easily display these routes by importing the array and mapping through it whenever needed.</p>
<pre><code class="lang-ts"><span class="hljs-comment">//📂./src/routes.ts</span>

<span class="hljs-keyword">import</span> { BiHomeAlt2 } <span class="hljs-keyword">from</span> <span class="hljs-string">"react-icons/bi"</span>;
<span class="hljs-keyword">import</span> { FiSearch } <span class="hljs-keyword">from</span> <span class="hljs-string">"react-icons/fi"</span>;
<span class="hljs-keyword">import</span> { PiChatCircleBold } <span class="hljs-keyword">from</span> <span class="hljs-string">"react-icons/pi"</span>;
<span class="hljs-keyword">import</span> { IoPricetagsOutline } <span class="hljs-keyword">from</span> <span class="hljs-string">"react-icons/io5"</span>;

<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> routes = [
  {
    title: <span class="hljs-string">"Home"</span>,
    href: <span class="hljs-string">"#"</span>,
    Icon: BiHomeAlt2,
  },
  {
    title: <span class="hljs-string">"Explore"</span>,
    href: <span class="hljs-string">"#"</span>,
    Icon: FiSearch,
  },
  {
    title: <span class="hljs-string">"Pricing"</span>,
    href: <span class="hljs-string">"#"</span>,
    Icon: IoPricetagsOutline,
  },
  {
    title: <span class="hljs-string">"About"</span>,
    href: <span class="hljs-string">"#"</span>,
    Icon: PiChatCircleBold,
  },
];
</code></pre>
<p>Each object within the <code>routes</code> array includes an icon imported from the <a target="_blank" href="https://react-icons.github.io/react-icons/">React Icons</a> library, a clear title, and an <code>href</code> that signifies the route's path.</p>
<p>Let's display the <code>routes</code> array on the navbar. Open up <code>./src/components/nav-desktop</code> and add the following code:</p>
<pre><code class="lang-tsx">//📂./src/components/nav-desktop.tsx

import { routes } from "../routes";

export const NavDesktop = () =&gt; {
  return (
    &lt;ul className="hidden lg:flex lg:items-center gap-5 text-sm"&gt;
      {routes.map((route) =&gt; {
        const { Icon, href, title } = route;
        return (
          &lt;li&gt;
            &lt;a
              href={href}
              className="flex items-center gap-1 hover:text-neutral-400 transition-all"
            &gt;
              &lt;Icon /&gt;
              {title}
            &lt;/a&gt;
          &lt;/li&gt;
        );
      })}
    &lt;/ul&gt;
  );
};
</code></pre>
<p>The <code>NavDesktop</code> component renders an unordered list (<code>ul</code>) containing routes. It uses the <code>routes</code> array imported from the <code>../routes</code> file to dynamically generate list items (<code>li</code>) with links (<code>a</code>) and icons.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/11/image-7.png" alt="Desktop navigation items" width="600" height="400" loading="lazy">
<em>Desktop Navigation</em></p>
<p>You've just built a beautiful desktop navigation bar, awesome! 🎉</p>
<p>Now that you have your desktop navbar in place, it's time to create the animated mobile menu. </p>
<h2 id="heading-how-to-create-an-animated-hamburger-icon-in-react">How to Create an Animated Hamburger Icon in React</h2>
<p>First, let's create a button with a hamburger icon. This button will allow users to toggle your mobile menu's visibility.</p>
<p><a target="_blank" href="https://hamburger-react.netlify.app/">Hamburger React</a> is an incredibly lightweight React library that provides a wide array of animated hamburger icons for smooth integration into your React applications.</p>
<p>While you certainly have the option to create your own animated hamburger icons from the ground up, in this tutorial, you'll utilize <a target="_blank" href="https://hamburger-react.netlify.app/">Hamburger React</a> to implement the animated hamburger icon and move on to building the animated mobile menu.</p>
<p>Open up <code>./src/components/nav-mobile.tsx</code> and add the following code:</p>
<pre><code class="lang-tsx">//📂./src/components/nav-mobile.tsx

import { useClickAway } from "react-use";
import { useRef } from "react";
import { useState } from "react";
import { Squash as Hamburger } from "hamburger-react";
import { AnimatePresence, motion } from "framer-motion";
import { routes } from "../routes";

export const NavMobile = () =&gt; {
  const [isOpen, setOpen] = useState(false);

  return (
    &lt;div className="lg:hidden "&gt;
      &lt;Hamburger toggled={isOpen} size={20} toggle={setOpen} /&gt;
    &lt;/div&gt;
  );
};
</code></pre>
<p>This React component creates a button that opens and closes a menu. The button starts as closed (<code>isOpen</code> is <code>false</code>). When clicked, it toggles the menu's visibility.</p>
<p>Additionally, the <code>NavMobile</code> component will remain hidden on larger screens, as you've already implemented the desktop navbar component.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/11/ezgif-2-a7c01fc67a.gif" alt="Clickable button at top right with hamburger icon. Clicking toggles between open and closed states will trigger smooth transitions." width="600" height="400" loading="lazy">
<em>Clickable hamburger icon. Toggling between open and closed states with smooth animations.</em></p>
<h2 id="heading-how-to-create-an-animated-mobile-menu-in-react">How to Create an Animated Mobile Menu in React</h2>
<p>Let's enhance the functionality of your mobile menu and display the navigation routes once the user clicks on the hamburger button.</p>
<p>Open up <code>./src/components/nav-mobile.tsx</code> and add the following code:</p>
<pre><code class="lang-tsx">//📂./src/components/nav-mobile.tsx

import { useClickAway } from "react-use";
import { useRef } from "react";
import { useState } from "react";
import { AnimatePresence, motion } from "framer-motion";
import { Squash as Hamburger } from "hamburger-react";
import { routes } from "../routes";

export const NavMobile = () =&gt; {
  const [isOpen, setOpen] = useState(false);
  const ref = useRef(null);

  useClickAway(ref, () =&gt; setOpen(false));

  return (
    &lt;div ref={ref} className="lg:hidden "&gt;
      &lt;Hamburger toggled={isOpen} size={20} toggle={setOpen} /&gt;
      {isOpen &amp;&amp; (
        &lt;div className="fixed left-0 shadow-4xl right-0 top-[3.5rem] p-5 pt-0 bg-neutral-950 border-b border-b-white/20"&gt;
          &lt;ul className="grid gap-2"&gt;
            {routes.map((route) =&gt; {
              const { Icon } = route;

              return (
                &lt;li
                  key={route.title}
                  className="w-full p-[0.08rem] rounded-xl bg-gradient-to-tr from-neutral-800 via-neutral-950 to-neutral-700"
                &gt;
                  &lt;a
                    onClick={() =&gt; setOpen((prev) =&gt; !prev)}
                    className={
                      "flex items-center justify-between w-full p-5 rounded-xl bg-neutral-950"
                    }
                    href={route.href}
                  &gt;
                    &lt;span className="flex gap-1 text-lg"&gt;{route.title}&lt;/span&gt;
                    &lt;Icon className="text-xl" /&gt;
                  &lt;/a&gt;
                &lt;/li&gt;
              );
            })}
          &lt;/ul&gt;
        &lt;/div&gt;
      )}
    &lt;/div&gt;
  );
};
</code></pre>
<p>Here's a simplified explanation of the component so far:</p>
<p><strong>Setting up State and Refs</strong>:</p>
<ul>
<li>The component starts by creating two variables: <code>isOpen</code> and <code>ref</code>.</li>
<li><code>isOpen</code> keeps track of whether the menu is open or closed.</li>
<li><code>ref</code> is like a label that we attach to an element in the HTML. In this case, it's used to reference the menu container.</li>
</ul>
<p><strong>Handling Clicks Outside the Menu</strong>:</p>
<ul>
<li>The component uses <code>useClickAway</code> hook from <a target="_blank" href="https://streamich.github.io/react-use/">React-Use</a> library to detect when a user clicks outside the menu. When this happens, it triggers a function that closes the menu by setting <code>isOpen</code> to <code>false</code>.</li>
</ul>
<p><strong>Rendering the Hamburger Button</strong>:</p>
<ul>
<li>The component renders a button that looks like a hamburger icon. This button serves as a toggle switch for opening and closing the menu.</li>
<li>When the button is clicked, it toggles the value of <code>isOpen</code>, which controls whether the menu is displayed or not.</li>
</ul>
<p><strong>Displaying the Menu</strong>:</p>
<ul>
<li>If <code>isOpen</code> is <code>true</code>, it means the menu should be displayed. In this case, a list of links and icons is shown.</li>
<li>Each link represents a different page or section. When a link is clicked, it updates <code>isOpen</code> to close the menu.</li>
</ul>
<p>That's the basic flow of this React component! It sets up state to keep track of the menu's open/closed status, handles clicks outside the menu, renders a button to toggle the menu, and displays the menu content when it's supposed to be open.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/11/ezgif-2-24c6a3c200.gif" alt="Once you click on the hamburger icon at the top right of the screen, you will be able to see the mobile menu and the navigation items. Clicking on the hamburger button will toggle the mobile menu's visibility " width="600" height="400" loading="lazy">
<em>Hamburger Menu Toggle Functionality</em></p>
<p>Now, let's use <a target="_blank" href="https://www.framer.com/motion/">Framer Motion</a> to animate the mobile menu. Open up <code>./src/components/nav-mobile.tsx</code> and add the following code:</p>
<pre><code class="lang-tsx">//📂./src/components/nav-mobile.tsx

import { useClickAway } from "react-use";
import { useRef } from "react";
import { useState } from "react";
import { AnimatePresence, motion } from "framer-motion";
import { Squash as Hamburger } from "hamburger-react";
import { routes } from "../routes";

export const NavMobile = () =&gt; {
  const [isOpen, setOpen] = useState(false);
  const ref = useRef(null);

  useClickAway(ref, () =&gt; setOpen(false));

  return (
    &lt;div ref={ref} className="lg:hidden "&gt;
      &lt;Hamburger toggled={isOpen} size={20} toggle={setOpen} /&gt;
      &lt;AnimatePresence&gt;
        {isOpen &amp;&amp; (
          &lt;motion.div
            initial={{ opacity: 0 }}
            animate={{ opacity: 1 }}
            exit={{ opacity: 0 }}
            transition={{ duration: 0.2 }}
            className="fixed left-0 shadow-4xl right-0 top-[3.5rem] p-5 pt-0 bg-neutral-950 border-b border-b-white/20"
          &gt;
            &lt;ul className="grid gap-2"&gt;
              {routes.map((route, idx) =&gt; {
                const { Icon } = route;

                return (
                  &lt;motion.li
                    initial={{ scale: 0, opacity: 0 }}
                    animate={{ scale: 1, opacity: 1 }}
                    transition={{
                      type: "spring",
                      stiffness: 260,
                      damping: 20,
                      delay: 0.1 + idx / 10,
                    }}
                    key={route.title}
                    className="w-full p-[0.08rem] rounded-xl bg-gradient-to-tr from-neutral-800 via-neutral-950 to-neutral-700"
                  &gt;
                    &lt;a
                      onClick={() =&gt; setOpen((prev) =&gt; !prev)}
                      className={
                        "flex items-center justify-between w-full p-5 rounded-xl bg-neutral-950"
                      }
                      href={route.href}
                    &gt;
                      &lt;span className="flex gap-1 text-lg"&gt;{route.title}&lt;/span&gt;
                      &lt;Icon className="text-xl" /&gt;
                    &lt;/a&gt;
                  &lt;/motion.li&gt;
                );
              })}
            &lt;/ul&gt;
          &lt;/motion.div&gt;
        )}
      &lt;/AnimatePresence&gt;
    &lt;/div&gt;
  );
};
</code></pre>
<p>Let's break down the motion-related parts:</p>
<p><strong>AnimatePresence</strong>:</p>
<p>The <code>AnimatePresence</code> component is a special container provided by the <code>framer-motion</code> library. It manages the lifecycle of animations for elements entering and leaving the DOM. </p>
<p>In this code, it wraps around the menu content, indicating that it should be animated when it appears or disappears.</p>
<p><strong>Menu Content Animation</strong>:</p>
<p>The menu content (the part that appears when the menu is open) is given animation instructions. These instructions include:</p>
<ul>
<li><code>initial</code>: This defines the starting state of the animation. Here, it's set to start with no opacity (completely invisible).</li>
<li><code>animate</code>: This defines how the animation progresses. It specifies that the opacity should go to 1 (fully visible), creating a fade-in effect.</li>
<li><code>exit</code>: This defines how the animation behaves when the menu content is removed from the DOM. Here, it sets the opacity to 0, creating a fade-out effect.</li>
<li><code>transition</code>: This controls how the animation behaves over time. In this case, it's set to have a duration of 0.2 seconds, meaning it takes 0.2 seconds for the animation to complete.</li>
</ul>
<p><strong>Link Item Animation</strong>:</p>
<p>Each individual link item in the menu is given animation instructions. These instructions include:</p>
<ul>
<li><code>initial</code>: This sets the starting state of the animation. It begins with the item small (scale 0) and completely invisible (opacity 0).</li>
<li><code>animate</code>: This defines how the animation progresses. It specifies that the item should grow to its regular size (scale 1) and become fully visible (opacity 1).</li>
<li><code>transition</code>: This determines the animation behavior. It's set to a "spring" animation, which gives a bouncy effect. The <code>stiffness</code> and <code>damping</code> values control the bounciness, while <code>delay</code> creates a staggered effect, causing each item to start its animation slightly later than the previous one.</li>
</ul>
<p>These animations add visual flair to the menu and menu items, making them transition smoothly when opening and closing.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/11/ezgif-5-e28e07a84d.gif" alt="A screen recording which displays a fully animated mobile menu. On large screen devices, the routes will be displayed normally as an urdorder list, but in small screen devices, you will see a hamburger icon. Once you click on the hamburger icon, you will be able to see the animated mobile menu items" width="600" height="400" loading="lazy">
<em>Animated Menu Items</em></p>
<p>Congratulations, now you have a fully animated Hamburger Menu, great job! 🎉</p>
<h2 id="heading-conclusion"><strong>Conclusion</strong></h2>
<p>In this tutorial, we integrated Framer Motion to craft a dynamic animated hamburger menu in React. By applying the techniques covered, you now possess the skills to enhance user navigation with smooth animations and interactive elements.</p>
<p>You can follow me on <a target="_blank" href="https://twitter.com/Yazdun">Twitter</a> where I share more useful tips on web development. Happy coding!</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Create a Fully Animated Sidebar in React.js using Framer Motion ]]>
                </title>
                <description>
                    <![CDATA[ By Yazdun Fadali Adding smooth and professional animations to your user interfaces can be a bit tricky. In this tutorial, I'll show you how to use Framer Motion in your React apps to create beautiful animations. This guide is perfect if you're new to... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/create-a-fully-animated-sidebar/</link>
                <guid isPermaLink="false">66d4617347a8245f78752ad2</guid>
                
                    <category>
                        <![CDATA[ animation ]]>
                    </category>
                
                    <category>
                        <![CDATA[ React ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Web Development ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ freeCodeCamp ]]>
                </dc:creator>
                <pubDate>Mon, 16 Oct 2023 23:49:46 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2023/10/Frame-11.jpg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>By Yazdun Fadali</p>
<p>Adding smooth and professional animations to your user interfaces can be a bit tricky. In this tutorial, I'll show you how to use Framer Motion in your React apps to create beautiful animations.</p>
<p>This guide is perfect if you're new to Framer Motion or just want to make your animations stand out. We'll walk through the steps together, making it easy to add those beautiful, professional touches to your projects. Let's get started!</p>
<h2 id="heading-what-are-we-going-to-build">What Are We Going to Build?</h2>
<p>During this tutorial, I'll guide you step by step through implementing a complete animated sidebar component in React and Framer Motion.</p>
<p>You can also checkout this in-depth <a target="_blank" href="https://youtu.be/5_DTV975MOI?si=StJd9XNDYAl_YN3m">video tutorial</a> I have created based on this article.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/10/ezgif-5-0b78748b45.gif" alt="dark-themed animated sidebar component" width="600" height="400" loading="lazy">
<em>Animated Sidebar component</em></p>
<h2 id="heading-getting-started">Getting Started</h2>
<p>To get started with this tutorial, I've prepared a boilerplate project for you which contains all the required dependencies, so you don't need to set up your project from scratch.</p>
<p>Simply clone the <a target="_blank" href="https://github.com/Yazdun/react-animated-sidebar/tree/starter">starter boilerplate</a> from the GitHub repository and then follow along with the tutorial. </p>
<ul>
<li>Starter Boilerplate: <a target="_blank" href="https://github.com/Yazdun/react-animated-sidebar/tree/starter">View on GitHub</a></li>
<li>Final Version: <a target="_blank" href="https://github.com/Yazdun/react-animated-sidebar">View on GitHub</a></li>
</ul>
<h2 id="heading-what-is-framer-motion">What is Framer Motion?</h2>
<p>Framer Motion is a simple yet powerful animation library for React. With Framer Motion, you can effortlessly add smooth and professional animations and interactions to your React projects. </p>
<p>Framer Motion allows you to create things like smoothly sliding buttons, fading in text, or even complex animations with just a few simple lines of code.</p>
<p>You might also find it interesting to know that Framer Motion is what powers Framer, a popular tool for professional web designers. So, it's trusted by the experts to create those cool animations you often see on really polished websites.</p>
<h2 id="heading-how-to-create-a-simple-navigation-bar-in-react">How to Create a Simple Navigation Bar in React</h2>
<p>In this section, you'll be creating a straightforward navigation bar. Simply open the <code>components/Navigation</code> file and insert the following code:</p>
<pre><code class="lang-jsx"><span class="hljs-comment">//📁components/Navigation</span>

<span class="hljs-keyword">import</span> { Sidebar } <span class="hljs-keyword">from</span> <span class="hljs-string">'./Sidebar'</span>
<span class="hljs-keyword">import</span> { FiGithub } <span class="hljs-keyword">from</span> <span class="hljs-string">'react-icons/fi'</span>

<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> Navigation = <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">nav</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"flex items-center justify-between px-5 py-2 border-b-2 border-zinc-800"</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"flex items-center gap-3"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">Sidebar</span> /&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>Animated Sidebar<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">a</span>
        <span class="hljs-attr">className</span>=<span class="hljs-string">"flex items-center gap-2 px-4 py-2 text-orange-400 bg-orange-700/20 rounded-xl"</span>
        <span class="hljs-attr">href</span>=<span class="hljs-string">""</span>
      &gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">FiGithub</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"text-lg"</span> /&gt;</span>
        Source Code
      <span class="hljs-tag">&lt;/<span class="hljs-name">a</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">nav</span>&gt;</span></span>
  )
}
</code></pre>
<p>This component renders a navigation bar on a web page. Within this navigation bar, there are two main sections. The first section includes the <code>Sidebar</code> component. The second section contains a link element styled like a button with an icon. </p>
<p>This code is essentially setting up a basic navigation interface with some predefined styles for a React application.</p>
<h2 id="heading-how-to-create-a-simple-sidebar-component-in-react">How to Create a Simple Sidebar Component in React</h2>
<p>In this section, you'll be building a simple sidebar component in React. First of all, let's open up <code>components/Sidebar</code> and add the following code:</p>
<pre><code class="lang-jsx"><span class="hljs-comment">//📁components/Sidebar</span>

<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> Sidebar = <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-keyword">const</span> [open, setOpen] = useState(<span class="hljs-literal">false</span>)
  <span class="hljs-keyword">const</span> ref = useRef(<span class="hljs-literal">null</span>)
  useClickAway(ref, <span class="hljs-function">() =&gt;</span> setOpen(<span class="hljs-literal">false</span>))
  <span class="hljs-keyword">const</span> toggleSidebar = <span class="hljs-function">() =&gt;</span> setOpen(<span class="hljs-function"><span class="hljs-params">prev</span> =&gt;</span> !prev)

  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">button</span>
        <span class="hljs-attr">onClick</span>=<span class="hljs-string">{toggleSidebar}</span>
        <span class="hljs-attr">className</span>=<span class="hljs-string">"p-3 border-2 border-zinc-800 rounded-xl"</span>
        <span class="hljs-attr">aria-label</span>=<span class="hljs-string">"toggle sidebar"</span>
      &gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">GiHamburgerMenu</span> /&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
      {open &amp;&amp; (
        <span class="hljs-tag">&lt;&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">div</span>
            <span class="hljs-attr">aria-hidden</span>=<span class="hljs-string">"true"</span>
            <span class="hljs-attr">className</span>=<span class="hljs-string">"fixed bottom-0 left-0 right-0 top-0 z-40 bg-[rgba(0,0,0,0.1)] backdrop-blur-sm"</span>
          &gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">div</span>
            <span class="hljs-attr">className</span>=<span class="hljs-string">"fixed top-0 bottom-0 left-0 z-50 w-full h-screen max-w-xs border-r-2 border-zinc-800 bg-zinc-900"</span>
            <span class="hljs-attr">ref</span>=<span class="hljs-string">{ref}</span>
            <span class="hljs-attr">aria-label</span>=<span class="hljs-string">"Sidebar"</span>
          &gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"flex items-center justify-between p-5 border-b-2 border-zinc-800"</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">span</span>&gt;</span>Welcome<span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">button</span>
                <span class="hljs-attr">onClick</span>=<span class="hljs-string">{toggleSidebar}</span>
                <span class="hljs-attr">className</span>=<span class="hljs-string">"p-3 border-2 border-zinc-800 rounded-xl"</span>
                <span class="hljs-attr">aria-label</span>=<span class="hljs-string">"close sidebar"</span>
              &gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">AiOutlineRollback</span> /&gt;</span>
              <span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
            <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">ul</span>&gt;</span>
              {items.map((item, idx) =&gt; {
                const { title, href, Icon } = item
                return (
                  <span class="hljs-tag">&lt;<span class="hljs-name">li</span> <span class="hljs-attr">key</span>=<span class="hljs-string">{title}</span>&gt;</span>
                    <span class="hljs-tag">&lt;<span class="hljs-name">a</span>
                      <span class="hljs-attr">onClick</span>=<span class="hljs-string">{toggleSidebar}</span>
                      <span class="hljs-attr">href</span>=<span class="hljs-string">{href}</span>
                      <span class="hljs-attr">className</span>=<span class="hljs-string">"flex items-center justify-between gap-5 p-5 transition-all border-b-2 hover:bg-zinc-900 border-zinc-800"</span>
                    &gt;</span>
                      <span class="hljs-tag">&lt;<span class="hljs-name">span</span>&gt;</span>{title}<span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
                      <span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>
                        <span class="hljs-tag">&lt;<span class="hljs-name">Icon</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"text-2xl"</span> /&gt;</span>
                      <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
                    <span class="hljs-tag">&lt;/<span class="hljs-name">a</span>&gt;</span>
                  <span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
                )
              })}
            <span class="hljs-tag">&lt;/<span class="hljs-name">ul</span>&gt;</span>
          <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
        <span class="hljs-tag">&lt;/&gt;</span></span>
      )}
    &lt;/&gt;
  )
}

<span class="hljs-keyword">const</span> items = [
  { <span class="hljs-attr">title</span>: <span class="hljs-string">'Home'</span>, <span class="hljs-attr">Icon</span>: BiHomeSmile, <span class="hljs-attr">href</span>: <span class="hljs-string">'#'</span> },
  { <span class="hljs-attr">title</span>: <span class="hljs-string">'About'</span>, <span class="hljs-attr">Icon</span>: BiUser },
  { <span class="hljs-attr">title</span>: <span class="hljs-string">'Contact'</span>, <span class="hljs-attr">Icon</span>: HiOutlineChatBubbleBottomCenterText, <span class="hljs-attr">href</span>: <span class="hljs-string">'#'</span> },
  { <span class="hljs-attr">title</span>: <span class="hljs-string">'Settings'</span>, <span class="hljs-attr">Icon</span>: FiSettings, <span class="hljs-attr">href</span>: <span class="hljs-string">'#'</span> },
  { <span class="hljs-attr">title</span>: <span class="hljs-string">'Shop'</span>, <span class="hljs-attr">Icon</span>: FiShoppingCart, <span class="hljs-attr">href</span>: <span class="hljs-string">'#'</span> },
]
</code></pre>
<p>This component creates a collapsible sidebar navigation menu. </p>
<p>When the sidebar button is clicked, the sidebar either opens or closes. Inside the sidebar, there are menu items like <code>Home</code> , <code>About</code>,  <code>Contact</code>, and so on represented by icons.   </p>
<p>Clicking on any of these items will perform an action, like navigating to a different page.   </p>
<p>The component also handles various interactions, such as clicking outside the sidebar to close it.   </p>
<p>Overall, this component sets up a functional and interactive sidebar menu for a web application. Here is how your sidebar looks like so far:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/10/ezgif-3-fc03bdde04.gif" alt="Preview of the simpe sidebar component" width="600" height="400" loading="lazy">
<em>Sidebar Component</em></p>
<p>While this sidebar functions perfectly, you may notice that there are no animations present. Let's now integrate Framer Motion and incorporate some smooth animations into this sidebar.</p>
<h2 id="heading-how-to-animate-react-components-with-framer-motion">How to Animate React Components with Framer Motion</h2>
<p>Now that you have a functional sidebar, let's enhance it with some animations to add a bit of flair. Open up <code>components/Sidebar</code> and add the following code:</p>
<pre><code class="lang-jsx"><span class="hljs-keyword">import</span> { useRef, useState } <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>
<span class="hljs-keyword">import</span> { GiHamburgerMenu } <span class="hljs-keyword">from</span> <span class="hljs-string">'react-icons/gi'</span>
<span class="hljs-keyword">import</span> { AnimatePresence, motion } <span class="hljs-keyword">from</span> <span class="hljs-string">'framer-motion'</span>
<span class="hljs-keyword">import</span> { useClickAway } <span class="hljs-keyword">from</span> <span class="hljs-string">'react-use'</span>
<span class="hljs-keyword">import</span> { AiOutlineRollback } <span class="hljs-keyword">from</span> <span class="hljs-string">'react-icons/ai'</span>
<span class="hljs-keyword">import</span> { BiHomeSmile, BiUser } <span class="hljs-keyword">from</span> <span class="hljs-string">'react-icons/bi'</span>
<span class="hljs-keyword">import</span> { HiOutlineChatBubbleBottomCenterText } <span class="hljs-keyword">from</span> <span class="hljs-string">'react-icons/hi2'</span>
<span class="hljs-keyword">import</span> { FiSettings, FiShoppingCart } <span class="hljs-keyword">from</span> <span class="hljs-string">'react-icons/fi'</span>

<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> Sidebar = <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-keyword">const</span> [open, setOpen] = useState(<span class="hljs-literal">false</span>)
  <span class="hljs-keyword">const</span> ref = useRef(<span class="hljs-literal">null</span>)
  useClickAway(ref, <span class="hljs-function">() =&gt;</span> setOpen(<span class="hljs-literal">false</span>))
  <span class="hljs-keyword">const</span> toggleSidebar = <span class="hljs-function">() =&gt;</span> setOpen(<span class="hljs-function"><span class="hljs-params">prev</span> =&gt;</span> !prev)

  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">button</span>
        <span class="hljs-attr">onClick</span>=<span class="hljs-string">{toggleSidebar}</span>
        <span class="hljs-attr">className</span>=<span class="hljs-string">"p-3 border-2 border-zinc-800 rounded-xl"</span>
        <span class="hljs-attr">aria-label</span>=<span class="hljs-string">"toggle sidebar"</span>
      &gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">GiHamburgerMenu</span> /&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">AnimatePresence</span> <span class="hljs-attr">mode</span>=<span class="hljs-string">"wait"</span> <span class="hljs-attr">initial</span>=<span class="hljs-string">{false}</span>&gt;</span>
        {open &amp;&amp; (
          <span class="hljs-tag">&lt;&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">motion.div</span>
              {<span class="hljs-attr">...framerSidebarBackground</span>}
              <span class="hljs-attr">aria-hidden</span>=<span class="hljs-string">"true"</span>
              <span class="hljs-attr">className</span>=<span class="hljs-string">"fixed bottom-0 left-0 right-0 top-0 z-40 bg-[rgba(0,0,0,0.1)] backdrop-blur-sm"</span>
            &gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">motion.div</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">motion.div</span>
              {<span class="hljs-attr">...framerSidebarPanel</span>}
              <span class="hljs-attr">className</span>=<span class="hljs-string">"fixed top-0 bottom-0 left-0 z-50 w-full h-screen max-w-xs border-r-2 border-zinc-800 bg-zinc-900"</span>
              <span class="hljs-attr">ref</span>=<span class="hljs-string">{ref}</span>
              <span class="hljs-attr">aria-label</span>=<span class="hljs-string">"Sidebar"</span>
            &gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"flex items-center justify-between p-5 border-b-2 border-zinc-800"</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">span</span>&gt;</span>Welcome<span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">button</span>
                  <span class="hljs-attr">onClick</span>=<span class="hljs-string">{toggleSidebar}</span>
                  <span class="hljs-attr">className</span>=<span class="hljs-string">"p-3 border-2 border-zinc-800 rounded-xl"</span>
                  <span class="hljs-attr">aria-label</span>=<span class="hljs-string">"close sidebar"</span>
                &gt;</span>
                  <span class="hljs-tag">&lt;<span class="hljs-name">AiOutlineRollback</span> /&gt;</span>
                <span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
              <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">ul</span>&gt;</span>
                {items.map((item, idx) =&gt; {
                  const { title, href, Icon } = item
                  return (
                    <span class="hljs-tag">&lt;<span class="hljs-name">li</span> <span class="hljs-attr">key</span>=<span class="hljs-string">{title}</span>&gt;</span>
                      <span class="hljs-tag">&lt;<span class="hljs-name">a</span>
                        <span class="hljs-attr">onClick</span>=<span class="hljs-string">{toggleSidebar}</span>
                        <span class="hljs-attr">href</span>=<span class="hljs-string">{href}</span>
                        <span class="hljs-attr">className</span>=<span class="hljs-string">"flex items-center justify-between gap-5 p-5 transition-all border-b-2 hover:bg-zinc-900 border-zinc-800"</span>
                      &gt;</span>
                        <span class="hljs-tag">&lt;<span class="hljs-name">motion.span</span> {<span class="hljs-attr">...framerText</span>(<span class="hljs-attr">idx</span>)}&gt;</span>{title}<span class="hljs-tag">&lt;/<span class="hljs-name">motion.span</span>&gt;</span>
                        <span class="hljs-tag">&lt;<span class="hljs-name">motion.div</span> {<span class="hljs-attr">...framerIcon</span>}&gt;</span>
                          <span class="hljs-tag">&lt;<span class="hljs-name">Icon</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"text-2xl"</span> /&gt;</span>
                        <span class="hljs-tag">&lt;/<span class="hljs-name">motion.div</span>&gt;</span>
                      <span class="hljs-tag">&lt;/<span class="hljs-name">a</span>&gt;</span>
                    <span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
                  )
                })}
              <span class="hljs-tag">&lt;/<span class="hljs-name">ul</span>&gt;</span>
            <span class="hljs-tag">&lt;/<span class="hljs-name">motion.div</span>&gt;</span>
          <span class="hljs-tag">&lt;/&gt;</span>
        )}
      <span class="hljs-tag">&lt;/<span class="hljs-name">AnimatePresence</span>&gt;</span>
    <span class="hljs-tag">&lt;/&gt;</span></span>
  )
}

<span class="hljs-keyword">const</span> items = [
  { <span class="hljs-attr">title</span>: <span class="hljs-string">'Home'</span>, <span class="hljs-attr">Icon</span>: BiHomeSmile, <span class="hljs-attr">href</span>: <span class="hljs-string">'#'</span> },
  { <span class="hljs-attr">title</span>: <span class="hljs-string">'About'</span>, <span class="hljs-attr">Icon</span>: BiUser },
  { <span class="hljs-attr">title</span>: <span class="hljs-string">'Contact'</span>, <span class="hljs-attr">Icon</span>: HiOutlineChatBubbleBottomCenterText, <span class="hljs-attr">href</span>: <span class="hljs-string">'#'</span> },
  { <span class="hljs-attr">title</span>: <span class="hljs-string">'Settings'</span>, <span class="hljs-attr">Icon</span>: FiSettings, <span class="hljs-attr">href</span>: <span class="hljs-string">'#'</span> },
  { <span class="hljs-attr">title</span>: <span class="hljs-string">'Shop'</span>, <span class="hljs-attr">Icon</span>: FiShoppingCart, <span class="hljs-attr">href</span>: <span class="hljs-string">'#'</span> },
]

<span class="hljs-keyword">const</span> framerSidebarBackground = {
  <span class="hljs-attr">initial</span>: { <span class="hljs-attr">opacity</span>: <span class="hljs-number">0</span> },
  <span class="hljs-attr">animate</span>: { <span class="hljs-attr">opacity</span>: <span class="hljs-number">1</span> },
  <span class="hljs-attr">exit</span>: { <span class="hljs-attr">opacity</span>: <span class="hljs-number">0</span>, <span class="hljs-attr">transition</span>: { <span class="hljs-attr">delay</span>: <span class="hljs-number">0.2</span> } },
  <span class="hljs-attr">transition</span>: { <span class="hljs-attr">duration</span>: <span class="hljs-number">0.3</span> },
}

<span class="hljs-keyword">const</span> framerSidebarPanel = {
  <span class="hljs-attr">initial</span>: { <span class="hljs-attr">x</span>: <span class="hljs-string">'-100%'</span> },
  <span class="hljs-attr">animate</span>: { <span class="hljs-attr">x</span>: <span class="hljs-number">0</span> },
  <span class="hljs-attr">exit</span>: { <span class="hljs-attr">x</span>: <span class="hljs-string">'-100%'</span> },
  <span class="hljs-attr">transition</span>: { <span class="hljs-attr">duration</span>: <span class="hljs-number">0.3</span> },
}

<span class="hljs-keyword">const</span> framerText = <span class="hljs-function"><span class="hljs-params">delay</span> =&gt;</span> {
  <span class="hljs-keyword">return</span> {
    <span class="hljs-attr">initial</span>: { <span class="hljs-attr">opacity</span>: <span class="hljs-number">0</span>, <span class="hljs-attr">x</span>: <span class="hljs-number">-50</span> },
    <span class="hljs-attr">animate</span>: { <span class="hljs-attr">opacity</span>: <span class="hljs-number">1</span>, <span class="hljs-attr">x</span>: <span class="hljs-number">0</span> },
    <span class="hljs-attr">transition</span>: {
      <span class="hljs-attr">delay</span>: <span class="hljs-number">0.5</span> + delay / <span class="hljs-number">10</span>,
    },
  }
}

<span class="hljs-keyword">const</span> framerIcon = {
  <span class="hljs-attr">initial</span>: { <span class="hljs-attr">scale</span>: <span class="hljs-number">0</span> },
  <span class="hljs-attr">animate</span>: { <span class="hljs-attr">scale</span>: <span class="hljs-number">1</span> },
  <span class="hljs-attr">transition</span>: {
    <span class="hljs-attr">type</span>: <span class="hljs-string">'spring'</span>,
    <span class="hljs-attr">stiffness</span>: <span class="hljs-number">260</span>,
    <span class="hljs-attr">damping</span>: <span class="hljs-number">20</span>,
    <span class="hljs-attr">delay</span>: <span class="hljs-number">1.5</span>,
  },
}
</code></pre>
<p>Now let's go through the changes you've just added to your sidebar component:</p>
<ul>
<li><strong><code>motion</code> from Framer Motion</strong>: <code>motion</code> is an element provided by the Framer Motion library. It's used to wrap other components or elements to enable animation effects. In this code, we've used it to animate different elements of the sidebar, such as background overlays and icons.</li>
<li><strong><code>AnimatePresence</code> from Framer Motion</strong>: <code>AnimatePresence</code> is a component from Framer Motion that helps us animate components when they are mounted or unmounted. It's used to wrap elements that may appear or disappear dynamically. In this code, we've used it to handle the animation when the sidebar opens or closes.</li>
<li><strong>Animation Objects</strong>: <code>framerSidebarBackground</code> – This object contains properties that define how the background overlay of the sidebar animates. It has three states: initial (when it's not visible), animate (when it's fully visible), and exit (when it's disappearing). <code>opacity</code> is used to control the transparency of the overlay. <code>transition</code> defines how the animation transitions between states, including the duration of the animation and a delay.</li>
<li><code>framerSidebarPanel</code>: This object defines the animation for the sidebar panel itself, controlling how it slides into view.</li>
<li><code>x</code> is used to set the horizontal position of the sidebar. Similar to <code>framerSidebarBackground</code>, it defines initial, animate, and exit states, as well as transition properties.</li>
<li><code>framerText</code> and <code>framerIcon</code>: These objects define animations for the text and icons within the sidebar items. They control properties like opacity, position (x), and scale to create smooth transitions and effects.</li>
</ul>
<p>These animation objects provide a structured way to define how different elements within the sidebar should animate when they appear or disappear. They use a combination of properties like opacity, position, and scale to animate your React components.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/10/ezgif-5-0b78748b45.gif" alt="dark-themed animated sidebar component" width="600" height="400" loading="lazy">
<em>Final result</em></p>
<p>Congratulations! You've successfully brought life to your sidebar using React and Framer Motion. 🎉</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>In this tutorial you learned how to create a fully animated sidebar using Framer Motion. </p>
<p>With this new skill, you're now equipped to add smooth, professional animations to your React applications. </p>
<p>The possibilities for creating impressive and intricate animations using Framer Motion are endless. </p>
<p>Don't hesitate to showcase your projects on <a target="_blank" href="https://twitter.com/Yazdun">Twitter with me</a> – I'd love to see your creative ideas come to life! </p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ CSS Transition vs Animation Handbook – How to Animate Elements in CSS ]]>
                </title>
                <description>
                    <![CDATA[ CSS transitions and animations provide smooth, gradual ways to change an element's style. But they work in different ways. Here are the main distinctions between them:                         ]]>
                </description>
                <link>https://www.freecodecamp.org/news/css-transition-vs-css-animation-handbook/</link>
                <guid isPermaLink="false">66ba0dea79b7f411df58de98</guid>
                
                    <category>
                        <![CDATA[ animation ]]>
                    </category>
                
                    <category>
                        <![CDATA[ CSS ]]>
                    </category>
                
                    <category>
                        <![CDATA[ handbook ]]>
                    </category>
                
                    <category>
                        <![CDATA[ transitions ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Oluwatobi Sofela ]]>
                </dc:creator>
                <pubDate>Tue, 12 Sep 2023 00:20:36 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2023/09/How-to-Animate-Elements-in-CSS-Cover.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>CSS transitions and animations provide smooth, gradual ways to change an element's style. But they work in different ways.</p>
<p>Here are the main distinctions between them:</p>
<table>
    <thead>
        <tr>
            <th>CSS Transition</th>
            <th>CSS Animation</th>
        </tr>
    </thead>
    <tbody>
        <tr>
            <td>
                <ul>
                    <li>
                        Creates smooth transitions from one CSS value to another.
                    </li>
                    <li>
                        You need triggers to run CSS transitions. For instance, you can use the <code>:hover</code> <a href="https://codesweetly.com/css-pseudo-selectors">pseudo-class</a> to run transitions when a user's pointer hovers over an element.
                    </li>
                    <li>
                        Transition has only two states: an initial and a final state. You cannot create intermediate steps.
                    </li>
                    <li>Runs only once.</li>
                    <li>Best used for basic style changes.</li>
                </ul>
            </td>
            <td>
                <ul>
                    <li>
                        Animates the style change from one CSS keyframe to another.
                    </li>
                    <li>CSS animations do not need triggers.</li>
                    <li>Animation allows you to create multiple states.</li>
                    <li>
                        You can run multiple animation iterations—even to infinity.
                    </li>
                    <li>Best used for dynamic style changes.</li>
                </ul>
            </td>
        </tr>
    </tbody>
</table>

<p>This handbook uses examples to explain the two animating techniques so that you can understand their similarities and differences.</p>
<h2 id="heading-table-of-contents">Table of Contents</h2>
<ol>
<li><a class="post-section-overview" href="#heading-what-are-css-transitions">What Are CSS Transitions?</a></li>
<li><a class="post-section-overview" href="#heading-categories-of-css-transition-properties">Categories of CSS Transition Properties</a><ul>
<li><a class="post-section-overview" href="#heading-what-are-the-required-css-transition-properties">What Are the Required CSS Transition Properties?</a></li>
<li><a class="post-section-overview" href="#heading-what-is-the-css-transition-property">What is the CSS <code>transition-property</code>?</a></li>
<li><a class="post-section-overview" href="#heading-what-is-the-css-transition-duration-property">What is the CSS <code>transition-duration</code> Property?</a></li>
<li><a class="post-section-overview" href="#heading-examples-of-the-required-css-transition-properties">Examples of the Required CSS Transition Properties</a></li>
<li><a class="post-section-overview" href="#heading-what-are-the-optional-css-transition-properties">What Are the Optional CSS Transition Properties?</a></li>
<li><a class="post-section-overview" href="#heading-what-is-the-css-transition-timing-function-property">What is the CSS <code>transition-timing-function</code> Property?</a></li>
<li><a class="post-section-overview" href="#what-is-a-css-transition-delay-property">What is the CSS <code>transition-delay</code> Property?</a></li>
<li><a class="post-section-overview" href="#heading-examples-of-the-optional-css-transition-properties">Examples of the Optional CSS Transition Properties</a></li>
</ul>
</li>
<li><a class="post-section-overview" href="#heading-shorthand-for-defining-the-css-transition-properties">Shorthand for Defining the CSS Transition Properties</a></li>
<li><a class="post-section-overview" href="#heading-what-is-css-animation">What is CSS Animation?</a><ul>
<li><a class="post-section-overview" href="#heading-components-of-css-animations">Components of CSS Animations</a></li>
<li><a class="post-section-overview" href="#heading-what-are-css-keyframes">What are CSS @keyframes?</a></li>
</ul>
</li>
<li><a class="post-section-overview" href="#heading-what-are-css-animation-properties">What Are CSS Animation Properties?</a><ul>
<li><a class="post-section-overview" href="#heading-what-is-the-css-animation-name-property">What is the CSS <code>animation-name</code> Property?</a></li>
<li><a class="post-section-overview" href="#heading-what-is-the-css-animation-duration-property">What is the CSS <code>animation-duration</code> Property?</a></li>
<li><a class="post-section-overview" href="#heading-what-is-the-css-animation-timing-function-property">What is the CSS <code>animation-timing-function</code> Property?</a></li>
<li><a class="post-section-overview" href="#heading-what-is-the-css-animation-delay-property">What is the CSS <code>animation-delay</code> Property?</a></li>
<li><a class="post-section-overview" href="#heading-what-is-the-css-animation-iteration-count-property">What is the CSS <code>animation-iteration-count</code> Property?</a></li>
<li><a class="post-section-overview" href="#heading-what-is-the-css-animation-direction-property">What is the CSS <code>animation-direction</code> Property?</a></li>
<li><a class="post-section-overview" href="#heading-what-is-the-css-animation-play-state-property">What is the CSS <code>animation-play-state</code> Property?</a></li>
<li><a class="post-section-overview" href="#heading-what-is-the-css-animation-fill-mode-property">What is the CSS <code>animation-fill-mode</code> Property?</a></li>
</ul>
</li>
<li><a class="post-section-overview" href="#what-is-a-css-animation-property">What is the CSS <code>animation</code> Property?</a></li>
<li><a class="post-section-overview" href="#heading-important-stuff-to-know-about-css-transitions-and-animations">Important Stuff to Know about CSS Transitions and Animations</a></li>
<li><a class="post-section-overview" href="#heading-wrapping-up">Wrapping up</a></li>
</ol>
<p>Without further ado, let's discuss CSS transitions.</p>
<h2 id="heading-what-are-css-transitions">What Are CSS Transitions?</h2>
<p><strong>CSS transitions</strong> provide a smooth and gradual way to change a specific CSS property's value.</p>
<p>So, instead of allowing browsers to change a property's value immediately, CSS transitions cause the change to happen smoothly over a specified period of time.</p>
<p>For instance, suppose you wish to change an element's size on hover. In that case, you have two options:</p>
<ol>
<li>Implement the change without CSS transitions.</li>
<li>Use CSS transitions to transition smoothly from the element's initial size to its new state.</li>
</ol>
<p>Let's see some examples of the two options.</p>
<h3 id="heading-how-to-change-an-images-size-on-mouse-hover-without-using-css-transitions">How to change an image's size on mouse hover without using CSS transitions</h3>
<pre><code class="lang-css"><span class="hljs-selector-tag">img</span> {
  <span class="hljs-attribute">width</span>: <span class="hljs-number">40%</span>;
}

<span class="hljs-selector-tag">img</span><span class="hljs-selector-pseudo">:hover</span> {
  <span class="hljs-attribute">width</span>: <span class="hljs-number">100%</span>;
}
</code></pre>
<p><a target="_blank" href="https://codesweetly.com/try-it-sdk/css/css-transitions/js-dsymqf"><strong>Try Editing It</strong></a></p>
<p>The code above instantaneously changes the image's size from its initial width (<code>40%</code>) to its new dimension (<code>100%</code>) because we did not use CSS transitions.</p>
<p>With CSS transitions, you will get a much more pleasing experience. Let's see an example below.</p>
<h3 id="heading-how-to-change-an-images-size-on-mouse-hover-with-css-transitions">How to change an image's size on mouse hover with CSS transitions</h3>
<pre><code class="lang-css"><span class="hljs-selector-tag">img</span> {
  <span class="hljs-attribute">width</span>: <span class="hljs-number">40%</span>;
  <span class="hljs-attribute">transition</span>: width <span class="hljs-number">3s</span> ease-out <span class="hljs-number">0.4s</span>;
}

<span class="hljs-selector-tag">img</span><span class="hljs-selector-pseudo">:hover</span> {
  <span class="hljs-attribute">width</span>: <span class="hljs-number">100%</span>;
}
</code></pre>
<p><a target="_blank" href="https://codesweetly.com/try-it-sdk/css/css-transitions/js-ufwgbu"><strong>Try Editing It</strong></a></p>
<p>The <code>transition</code> property applied a smooth and gradual transition from <code>width: 40%</code> to <code>width: 100%</code> on the image.</p>
<h2 id="heading-categories-of-css-transition-properties">Categories of CSS Transition Properties</h2>
<p>We have two categories of CSS transition properties:</p>
<ul>
<li><em>Required</em> transition properties</li>
<li><em>Optional</em> transition properties</li>
</ul>
<p>Let's discuss the two.</p>
<h3 id="heading-what-are-the-required-css-transition-properties">What Are the Required CSS Transition Properties?</h3>
<p>The two required properties you need to create CSS transitions are:</p>
<ul>
<li><code>transition-property</code></li>
<li><code>transition-duration</code></li>
</ul>
<h4 id="heading-what-is-the-css-transition-property">What is the CSS transition-property?</h4>
<p>The CSS <code>transition-property</code> specifies the CSS property you wish to transition from its initial to its new state.</p>
<h4 id="heading-what-is-the-css-transition-duration-property">What is the CSS transition-duration Property?</h4>
<p>The CSS <code>transition-duration</code> property defines the length of time in which browsers should complete the selected element's transition. In other words, <code>transition-duration</code> sets the total start-to-finish time.</p>
<p><strong>Note the following:</strong></p>
<ul>
<li>The <code>transition-duration</code> property only accepts time in milliseconds (ms) or seconds (s).</li>
<li>Zero seconds (<code>0s</code>) is the <code>transition-duration</code>'s default value. Therefore, no <a target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/API/Element/transitionend_event">transition event</a> will occur if you do not define a <code>transition-duration</code> property.</li>
<li><code>transition-duration</code> accepts only a zero (<code>0</code>) or a positive numeric value. Browsers will ignore the duration declaration if you provide anything else.</li>
</ul>
<h3 id="heading-examples-of-the-required-css-transition-properties">Examples of the Required CSS Transition Properties</h3>
<p>Below are some examples of the two required CSS transition properties.</p>
<h4 id="heading-how-to-transition-an-elements-width-within-three-seconds">How to transition an element's width within three seconds</h4>
<pre><code class="lang-css"><span class="hljs-selector-tag">img</span> {
  <span class="hljs-attribute">width</span>: <span class="hljs-number">40%</span>;
  <span class="hljs-attribute">transition-property</span>: width;
  <span class="hljs-attribute">transition-duration</span>: <span class="hljs-number">3s</span>;
}

<span class="hljs-selector-tag">img</span><span class="hljs-selector-pseudo">:hover</span> {
  <span class="hljs-attribute">width</span>: <span class="hljs-number">100%</span>;
}
</code></pre>
<p><a target="_blank" href="https://codesweetly.com/try-it-sdk/css/css-transitions/js-cq27rd"><strong>Try Editing It</strong></a></p>
<p>Here's what we did in the snippet above:</p>
<ol>
<li>The <code>transition-property</code> tells browsers to transition the <code>img</code>'s <code>width</code> from its initial value (<code>40%</code>) to its new state (<code>100%</code>).</li>
<li>We used the <code>transition-duration</code> property to define three seconds (<code>3s</code>) duration from the start to the end of the transition.</li>
</ol>
<p>Therefore, instead of an instantaneous change from the image's initial width (<code>40%</code>) to its new size (<code>100%</code>), browsers will transition smoothly between the old and new state in three seconds (<code>3s</code>).</p>
<h4 id="heading-how-to-transition-a-fonts-size-within-five-seconds">How to transition a font's size within five seconds</h4>
<pre><code class="lang-css"><span class="hljs-selector-tag">p</span> {
  <span class="hljs-attribute">font-size</span>: <span class="hljs-number">1rem</span>;
  <span class="hljs-attribute">transition-property</span>: font-size;
  <span class="hljs-attribute">transition-duration</span>: <span class="hljs-number">5s</span>;
}

<span class="hljs-selector-tag">p</span><span class="hljs-selector-pseudo">:hover</span> {
  <span class="hljs-attribute">font-size</span>: <span class="hljs-number">7rem</span>;
}
</code></pre>
<p><a target="_blank" href="https://codesweetly.com/try-it-sdk/css/css-transitions/js-huvkzp"><strong>Try Editing It</strong></a></p>
<p>Here's what we did in the snippet above:</p>
<ol>
<li>The <code>transition-property</code> informs browsers to transition the <code>p</code> element's <code>font-size</code>.</li>
<li>We used the <code>transition-duration</code> property to define a five-second (<code>5s</code>) duration from the start to the end of the transition.</li>
</ol>
<p>Therefore, instead of an immediate change from the paragraph's initial font size (<code>1rem</code>) to its new size (<code>7rem</code>), browsers will transition smoothly between the old and new state in five seconds (<code>5s</code>).</p>
<p>Let's now discuss the optional CSS transition properties.</p>
<h3 id="heading-what-are-the-optional-css-transition-properties">What Are the Optional CSS Transition Properties?</h3>
<p>The two optional CSS transition properties are:</p>
<ul>
<li><code>transition-timing-function</code></li>
<li><code>transition-delay</code></li>
</ul>
<h4 id="heading-what-is-the-css-transition-timing-function-property">What is the CSS transition-timing-function Property?</h4>
<p>The CSS <code>transition-timing-function</code> property defines the implementation timing (speed) of the selected element's transition.</p>
<p>In other words, the <code>transition-timing-function</code> specifies the speed for implementing the transition at various intervals of its duration.</p>
<p>The values the <code>transition-timing-function</code> property accepts are:</p>
<ul>
<li><code>ease</code>: Starts the transition slowly. Then, speeds it up and ends it slowly. <code>ease</code> is the <code>transition-timing-function</code> property's default value. It is equivalent to <code>cubic-bezier(0.25,0.1,0.25,1)</code>.</li>
<li><code>ease-in</code>: Starts the transition slowly with a gradual increase in speed. It is equal to <code>cubic-bezier(0.42,0,1,1)</code>.</li>
<li><code>ease-out</code>: Starts fast and ends the transition slowly. It is equivalent to <code>cubic-bezier(0,0,0.58,1)</code>.</li>
<li><code>ease-in-out</code>: Starts and ends the transition slowly. It is equal to <code>cubic-bezier(0.42,0,0.58,1)</code>.</li>
<li><code>linear</code>: Starts and ends the transition using a consistent speed throughout the transition's duration. It is equivalent to <code>cubic-bezier(0,0,1,1)</code>.</li>
<li><code>cubic-bezier(p1, p2, p3, p4)</code>: Allows you to define the values of the <a target="_blank" href="https://www.cssportal.com/css-cubic-bezier-generator/">cubic-bezier curve</a>.</li>
</ul>
<h3 id="heading-what-is-the-css-transition-delay-property">What is the CSS transition-delay Property?</h3>
<p>The CSS <code>transition-delay</code> property defines how long the browser should wait before it starts the transition.</p>
<p><strong>Note the following:</strong></p>
<ul>
<li>The <code>transition-delay</code> property must be in milliseconds (ms) or seconds (s).</li>
<li><code>0s</code> is the <code>transition-delay</code>'s default value. It causes the transition to start immediately from the moment browsers apply it to an HTML element.</li>
<li>A negative value causes the transition to begin immediately from the specified time. For instance, suppose an element's <code>transition-delay</code> value is <code>-3s</code>. In that case, the transition will start immediately at 3 seconds.</li>
<li>A positive value causes the transition to begin after the specified delay time has elapsed. For instance, suppose an element's <code>transition-delay</code> value is <code>3s</code>. In that case, the transition will start after a 3-second delay.</li>
</ul>
<h3 id="heading-examples-of-the-optional-css-transition-properties">Examples of the Optional CSS Transition Properties</h3>
<p>Below are some examples of the two optional CSS transition properties.</p>
<h4 id="heading-how-to-transition-an-elements-width-with-an-ease-out-speed">How to transition an element's width with an ease-out speed</h4>
<pre><code class="lang-css"><span class="hljs-selector-tag">img</span> {
  <span class="hljs-attribute">width</span>: <span class="hljs-number">40%</span>;
  <span class="hljs-attribute">transition-property</span>: width;
  <span class="hljs-attribute">transition-duration</span>: <span class="hljs-number">3s</span>;
  <span class="hljs-attribute">transition-timing-function</span>: ease-out;
}

<span class="hljs-selector-tag">img</span><span class="hljs-selector-pseudo">:hover</span> {
  <span class="hljs-attribute">width</span>: <span class="hljs-number">100%</span>;
}
</code></pre>
<p><a target="_blank" href="https://codesweetly.com/try-it-sdk/css/css-transitions/js-tqzgmf"><strong>Try Editing It</strong></a></p>
<p>Here's what we did in the snippet above:</p>
<ol>
<li>The <code>transition-property</code> informs browsers to transition the <code>img</code> element's width.</li>
<li>We used the <code>transition-duration</code> property to define three seconds (<code>3s</code>) duration from the start to the end of the transition.</li>
<li>We used the <code>transition-timing-function</code> property to begin the transition quickly and end it slowly.</li>
</ol>
<h4 id="heading-how-to-transition-an-elements-width-with-a-linear-speed">How to transition an element's width with a linear speed</h4>
<pre><code class="lang-css"><span class="hljs-selector-tag">img</span> {
  <span class="hljs-attribute">width</span>: <span class="hljs-number">40%</span>;
  <span class="hljs-attribute">transition-property</span>: width;
  <span class="hljs-attribute">transition-duration</span>: <span class="hljs-number">3s</span>;
  <span class="hljs-attribute">transition-timing-function</span>: linear;
}

<span class="hljs-selector-tag">img</span><span class="hljs-selector-pseudo">:hover</span> {
  <span class="hljs-attribute">width</span>: <span class="hljs-number">100%</span>;
}
</code></pre>
<p><a target="_blank" href="https://codesweetly.com/try-it-sdk/css/css-transitions/js-1gqwai"><strong>Try Editing It</strong></a></p>
<p>Here's what we did in the snippet above:</p>
<ol>
<li>The <code>transition-property</code> informs browsers to transition the <code>img</code> element's width.</li>
<li>We used the <code>transition-duration</code> property to define three seconds (<code>3s</code>) duration from the start to the end of the transition.</li>
<li>The <code>transition-timing-function</code> property tells browsers to transition from the element's initial width to its new size using a consistent transition speed throughout.</li>
</ol>
<h4 id="heading-how-to-transition-an-elements-width-with-a-two-second-delay">How to transition an element's width with a two-second delay</h4>
<pre><code class="lang-css"><span class="hljs-selector-tag">img</span> {
  <span class="hljs-attribute">width</span>: <span class="hljs-number">40%</span>;
  <span class="hljs-attribute">transition-property</span>: width;
  <span class="hljs-attribute">transition-duration</span>: <span class="hljs-number">3s</span>;
  <span class="hljs-attribute">transition-timing-function</span>: linear;
  <span class="hljs-attribute">transition-delay</span>: <span class="hljs-number">2s</span>;
}

<span class="hljs-selector-tag">img</span><span class="hljs-selector-pseudo">:hover</span> {
  <span class="hljs-attribute">width</span>: <span class="hljs-number">100%</span>;
}
</code></pre>
<p><a target="_blank" href="https://codesweetly.com/try-it-sdk/css/css-transitions/js-ejjufi"><strong>Try Editing It</strong></a></p>
<p>Here's what we did in the snippet above:</p>
<ol>
<li>The <code>transition-property</code> informs browsers to transition the <code>img</code> element's <code>width</code> property.</li>
<li>We used the <code>transition-duration</code> property to define three seconds (<code>3s</code>) duration from the start to the end of the transition.</li>
<li>The <code>transition-timing-function</code> property transitions the <code>img</code> element's width using a consistent transition speed.</li>
<li>We used the <code>transition-delay</code> property to apply a two-second (<code>2s</code>) delay to the starting time of the transition.</li>
</ol>
<p>Now that we know the CSS transition properties, we can discuss defining them with a shorthand syntax.</p>
<h2 id="heading-shorthand-for-defining-the-css-transition-properties">Shorthand for Defining the CSS Transition Properties</h2>
<p>We use the <code>transition</code> property as shorthand for the <code>transition-property</code>, <code>transition-duration</code>, <code>transition-timing-function</code>, and <code>transition-delay</code> properties.</p>
<p>In other words, instead of writing:</p>
<pre><code class="lang-css"><span class="hljs-selector-tag">img</span> {
  <span class="hljs-attribute">transition-property</span>: width;
  <span class="hljs-attribute">transition-duration</span>: <span class="hljs-number">3s</span>;
  <span class="hljs-attribute">transition-timing-function</span>: linear;
  <span class="hljs-attribute">transition-delay</span>: <span class="hljs-number">2s</span>;
}
</code></pre>
<p>You can alternatively use the <code>transition</code> property to shorten your code like so:</p>
<pre><code class="lang-css"><span class="hljs-selector-tag">img</span> {
  <span class="hljs-attribute">transition</span>: width <span class="hljs-number">3s</span> linear <span class="hljs-number">2s</span>;
}
</code></pre>
<p><a target="_blank" href="https://codesweetly.com/try-it-sdk/css/css-transitions/js-vtvbpo"><strong>Try Editing It</strong></a></p>
<p>Here is the <code>transition</code> property's syntax:</p>
<pre><code class="lang-css"><span class="hljs-selector-tag">transition</span>: &lt;<span class="hljs-selector-tag">property-name</span>&gt; &lt;<span class="hljs-selector-tag">duration</span>&gt; &lt;<span class="hljs-selector-tag">timing-function</span>&gt; &lt;<span class="hljs-selector-tag">delay</span>&gt;;
</code></pre>
<p>Note that you can use the <code>transition</code> property to transition the state of multiple CSS properties.</p>
<p><strong>Here's an example:</strong></p>
<pre><code class="lang-css"><span class="hljs-selector-tag">img</span> {
  <span class="hljs-attribute">width</span>: <span class="hljs-number">40%</span>;
  <span class="hljs-attribute">opacity</span>: <span class="hljs-number">0.4</span>;
  <span class="hljs-attribute">transition</span>: width <span class="hljs-number">3s</span> linear, opacity <span class="hljs-number">4s</span> ease-out, transform <span class="hljs-number">5s</span>;
}

<span class="hljs-selector-tag">img</span><span class="hljs-selector-pseudo">:hover</span> {
  <span class="hljs-attribute">width</span>: <span class="hljs-number">100%</span>;
  <span class="hljs-attribute">opacity</span>: <span class="hljs-number">1</span>;
  <span class="hljs-attribute">transform</span>: <span class="hljs-built_in">rotate</span>(<span class="hljs-number">45deg</span>);
}
</code></pre>
<p><a target="_blank" href="https://codesweetly.com/try-it-sdk/css/css-transitions/js-ajygzm"><strong>Try Editing It</strong></a></p>
<p>The snippet above used commas (<code>,</code>) to separate each of the transitional properties we are applying to the <code>img</code> element.</p>
<p>So, now that we know what CSS transitions are and how they work, we can discuss CSS animations.</p>
<h2 id="heading-what-is-css-animation">What is CSS Animation?</h2>
<p><strong>CSS animations</strong> provide a smooth and gradual way to animate an element's style changes from one keyframe to another.</p>
<h3 id="heading-components-of-css-animations">Components of CSS Animations</h3>
<p>CSS animations consist of two components:</p>
<ol>
<li>Keyframes</li>
<li>Animation properties</li>
</ol>
<h3 id="heading-what-are-css-keyframes">What are CSS @keyframes?</h3>
<p><strong>@keyframes</strong> define the styles you want browsers to apply smoothly to an element at some specified key moments (frames).</p>
<h3 id="heading-syntax-of-css-keyframes">Syntax of CSS @keyframes</h3>
<p>A CSS @keyframes <a target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/CSS/At-rule">at-rule</a> consists of the following:</p>
<ol>
<li>An <code>@keyframes</code> keyword</li>
<li>The <code>@keyframes</code>' name</li>
<li>A block of zero or more keyframes</li>
<li>The animation's key moment selector</li>
<li>The key moment's style declarations</li>
</ol>
<p><strong>Here's an illustration:</strong></p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/09/css-animation-keyframes-illustration-codesweetly.png" alt="Anatomy of CSS @keyframes at-rule" width="600" height="400" loading="lazy">
<em>A CSS @keyframes at-rule consists of a keyword, a name, and a block of keyframes</em></p>
<h3 id="heading-examples-of-css-keyframes">Examples of CSS @keyframes</h3>
<p>Below are examples of the CSS @keyframes.</p>
<h4 id="heading-how-to-define-change-colors-keyframes">How to define <code>change-color</code>'s keyframes</h4>
<pre><code class="lang-css"><span class="hljs-keyword">@keyframes</span> change-color {
  <span class="hljs-comment">/* The first keyframe */</span>
  0% {<span class="hljs-attribute">background-color</span>: purple;}
  <span class="hljs-comment">/* The last keyframe */</span>
  100% {<span class="hljs-attribute">background-color</span>: yellow;}
}
</code></pre>
<p>Here's what we did in the snippet above:</p>
<ol>
<li>We created the <code>@keyframes</code> at-rule named <code>change-color</code>.</li>
<li>We defined a keyframe for browsers to apply when an associated element's animation is at its zero percent (<code>0%</code>) duration.</li>
<li>We defined a keyframe for browsers to apply when an associated element's animation is at its one hundred percent (<code>100%</code>) duration.</li>
</ol>
<p><strong>Note:</strong></p>
<ul>
<li>You can name your <code>@keyframes</code> anything you wish.</li>
<li><code>0%</code> is equivalent to the keyword <code>from</code>. And <code>100%</code> is the same as the keyword <code>to</code>. In other words, the snippet above is equal to the following:</li>
</ul>
<pre><code class="lang-css"><span class="hljs-keyword">@keyframes</span> change-color {
  <span class="hljs-comment">/* The first keyframe */</span>
  <span class="hljs-selector-tag">from</span> {<span class="hljs-attribute">background-color</span>: purple;} 
  <span class="hljs-comment">/* The last keyframe */</span>
  <span class="hljs-selector-tag">to</span> {<span class="hljs-attribute">background-color</span>: yellow;} 
}
</code></pre>
<ul>
<li>An animation's start and end states (<code>from</code> and <code>to</code>) are optional.</li>
<li>Suppose you omit an <code>@keyframes</code>' start (<code>0%</code>) or end (<code>100%</code>) state. In that case, browsers will default to the element's existing styles for either state.</li>
<li>The important rule (<code>!important</code>) does not work in keyframes. Browsers will ignore any keyframe declaration with an <code>!important</code> rule.</li>
</ul>
<p>Let's see another example.</p>
<h4 id="heading-how-to-define-shape-images-keyframes">How to define <code>shape-image</code>'s keyframes</h4>
<pre><code class="lang-css"><span class="hljs-keyword">@keyframes</span> shape-image {
  0% { <span class="hljs-attribute">width</span>: <span class="hljs-number">40%</span>; <span class="hljs-attribute">border</span>: <span class="hljs-number">5px</span> solid blue;}
  40% { <span class="hljs-attribute">width</span>: <span class="hljs-number">70%</span>; <span class="hljs-attribute">border</span>: <span class="hljs-number">1px</span> solid red; <span class="hljs-attribute">border-radius</span>: <span class="hljs-number">50%</span>;}
  75% { <span class="hljs-attribute">width</span>: <span class="hljs-number">50%</span>; <span class="hljs-attribute">border</span>: <span class="hljs-number">30px</span> solid green;}
  100% { <span class="hljs-attribute">width</span>: <span class="hljs-number">100%</span>; <span class="hljs-attribute">border</span>: <span class="hljs-number">7px</span> solid purple;}
}
</code></pre>
<p>Here's what we did in the snippet above:</p>
<ol>
<li>We created the <code>@keyframes</code> <a target="_blank" href="https://codesweetly.com/css-ruleset">ruleset</a> named <code>shape-image</code>.</li>
<li>We defined four keyframes for browsers to apply when an associated element's animation is at the specified key moments.</li>
</ol>
<p><strong>Tip:</strong> Use the <a target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/API/CSSKeyframesRule">CSSKeyframesRule</a> interface in JavaScript to access the CSS <code>@keyframes</code> at-rules.</p>
<p>So, now that we know the CSS @keyframes ruleset, we can discuss the other component of CSS animations—<em>animation properties</em>.</p>
<h2 id="heading-what-are-css-animation-properties">What Are CSS Animation Properties?</h2>
<p><strong>CSS animation properties</strong> inform browsers about the animation you wish to apply to a specific element.</p>
<p>In other words, CSS animation properties describe the animation's attributes, such as its name, duration, direction, and iteration.</p>
<p>The nine (9) types of CSS animation properties are:</p>
<ul>
<li><code>animation-name</code></li>
<li><code>animation-duration</code></li>
<li><code>animation-timing-function</code></li>
<li><code>animation-delay</code></li>
<li><code>animation-iteration-count</code></li>
<li><code>animation-direction</code></li>
<li><code>animation-play-state</code></li>
<li><code>animation-fill-mode</code></li>
<li><code>animation</code></li>
</ul>
<p>Let's discuss each one now.</p>
<h3 id="heading-what-is-the-css-animation-name-property">What is the CSS <code>animation-name</code> property?</h3>
<p>The CSS <code>animation-name</code> property defines the name of the <code>@keyframes</code> at-rules containing the styles you wish to apply to a specific element.</p>
<p><strong>Here's an example:</strong></p>
<pre><code class="lang-css"><span class="hljs-selector-tag">div</span> {
  <span class="hljs-attribute">width</span>: <span class="hljs-number">150px</span>;
  <span class="hljs-attribute">height</span>: <span class="hljs-number">150px</span>;
  <span class="hljs-attribute">animation-name</span>: change-color;
}

<span class="hljs-keyword">@keyframes</span> change-color {
  <span class="hljs-selector-tag">from</span> {<span class="hljs-attribute">background-color</span>: purple;}
  <span class="hljs-selector-tag">to</span> {<span class="hljs-attribute">background-color</span>: yellow;}
}
</code></pre>
<p>Here's what we did in the snippet above:</p>
<ol>
<li>The <code>animation-name</code> property specifies the <code>@keyframes</code> we wish to apply to the <code>div</code> element.</li>
<li>We created <code>change-color</code>'s <code>@keyframes</code> ruleset.</li>
<li>We defined two keyframes for browsers to use when the <code>div</code> element's animation is at its zero percent (<code>0%</code>) and one hundred percent (<code>100%</code>) duration.</li>
</ol>
<p><strong>Tip:</strong> You can use the keyword <code>none</code> to deactivate an animation.</p>
<h3 id="heading-what-is-the-css-animation-duration-property">What is the CSS <code>animation-duration</code> property?</h3>
<p>The CSS <code>animation-duration</code> property defines the time to complete one animation cycle.</p>
<p><strong>Note the following:</strong></p>
<ul>
<li>The <code>animation-duration</code> property must be in milliseconds (ms) or seconds (s) units.</li>
<li><code>animation-duration</code>'s value must be zero or positive. Otherwise, browsers will ignore the duration declaration.</li>
<li>Zero seconds (<code>0s</code>) is <code>animation-duration</code>'s default value.</li>
<li>Suppose <code>0s</code> is <code>animation-duration</code>'s value. In that case, browsers will still execute the animation by firing the <a target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/API/Element/animationstart_event"><code>animationStart</code></a> and <a target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/API/Element/animationend_event"><code>animationEnd</code></a> events. But the <a target="_blank" href="https://codesweetly.com/css-animations-explained#what-is-an-animation-fill-mode-property-in-css"><code>animation-fill-mode</code></a>'s value will determine whether the animation is visible. For instance, if you set the <code>animation-fill-mode</code> to <code>none</code>, the animation will be invisible.</li>
</ul>
<p>Let's see some examples of the <code>animation-duration</code> property.</p>
<h4 id="heading-how-to-animate-an-elements-color-change-within-three-seconds">How to animate an element's color change within three seconds</h4>
<pre><code class="lang-css"><span class="hljs-selector-tag">div</span> {
  <span class="hljs-attribute">width</span>: <span class="hljs-number">150px</span>;
  <span class="hljs-attribute">height</span>: <span class="hljs-number">150px</span>;
  <span class="hljs-attribute">animation-name</span>: change-color;
  <span class="hljs-attribute">animation-duration</span>: <span class="hljs-number">3s</span>;
}

<span class="hljs-keyword">@keyframes</span> change-color {
  <span class="hljs-selector-tag">from</span> {<span class="hljs-attribute">background-color</span>: purple;}
  <span class="hljs-selector-tag">to</span> {<span class="hljs-attribute">background-color</span>: yellow;}
}
</code></pre>
<p><a target="_blank" href="https://codesweetly.com/try-it-sdk/css/css-animations/js-h6mb4k"><strong>Try Editing It</strong></a></p>
<p>Here's what we did in the snippet above:</p>
<ol>
<li>The <code>animation-name</code> property specifies the <code>@keyframes</code> we wish to apply to the <code>div</code> element.</li>
<li>The <code>animation-duration</code> property sets the animation's runtime for one cycle to three seconds (<code>3s</code>).</li>
<li>We created <code>change-color</code>'s @keyframes <a target="_blank" href="https://codesweetly.com/css-ruleset">ruleset</a>.</li>
<li>We defined two keyframes for browsers to apply when the <code>div</code> element's animation is at zero percent (<code>0%</code>) and one hundred percent (<code>100%</code>) duration.</li>
</ol>
<p>Therefore, browsers will create a smooth three-second animation from <code>change-color</code>'s first keyframe to its last.</p>
<h4 id="heading-how-to-animate-an-images-border-and-width-changes-within-seven-seconds">How to animate an image's border and width changes within seven seconds</h4>
<pre><code class="lang-css"><span class="hljs-selector-tag">img</span> {
  <span class="hljs-attribute">animation-name</span>: shape-image;
  <span class="hljs-attribute">animation-duration</span>: <span class="hljs-number">7s</span>;
}

<span class="hljs-keyword">@keyframes</span> shape-image {
  0% { <span class="hljs-attribute">width</span>: <span class="hljs-number">40%</span>; <span class="hljs-attribute">border</span>: <span class="hljs-number">5px</span> solid blue;}
  40% { <span class="hljs-attribute">width</span>: <span class="hljs-number">70%</span>; <span class="hljs-attribute">border</span>: <span class="hljs-number">1px</span> solid red; <span class="hljs-attribute">border-radius</span>: <span class="hljs-number">50%</span>;}
  75% { <span class="hljs-attribute">width</span>: <span class="hljs-number">50%</span>; <span class="hljs-attribute">border</span>: <span class="hljs-number">30px</span> solid green;}
  100% { <span class="hljs-attribute">width</span>: <span class="hljs-number">100%</span>; <span class="hljs-attribute">border</span>: <span class="hljs-number">7px</span> solid purple;}
}
</code></pre>
<p><a target="_blank" href="https://codesweetly.com/try-it-sdk/css/css-animations/js-prumgo"><strong>Try Editing It</strong></a></p>
<p>Here's what we did in the snippet above:</p>
<ol>
<li>The <code>animation-name</code> property specifies the <code>@keyframes</code> we wish to apply to the <code>img</code> element.</li>
<li>The <code>animation-duration</code> property sets the animation's runtime for one cycle to seven seconds (<code>7s</code>).</li>
<li>We created <code>shape-image</code>'s @keyframes ruleset.</li>
<li>We defined four keyframes for browsers to apply when the image's animation is at the specified key moments.</li>
</ol>
<p>Therefore, browsers will create a smooth seven-second animation from <code>shape-image</code>'s first keyframe to its last.</p>
<h3 id="heading-what-is-the-css-animation-timing-function-property">What is the CSS <code>animation-timing-function</code> property?</h3>
<p>The CSS <code>animation-timing-function</code> property defines an animation's implementation timing (speed) throughout its duration.</p>
<p>In other words, the <code>animation-timing-function</code> property specifies the speed for implementing the animation at various intervals of its duration.</p>
<p>The values the <code>animation-timing-function</code> property accepts are:</p>
<ul>
<li><code>ease</code>: Starts the animation slowly. Then speeds it up and ends it slowly. <code>ease</code> is the <code>animation-timing-function</code> property's default value. It is equivalent to <code>cubic-bezier(0.25, 0.1, 0.25, 1)</code>.</li>
<li><code>ease-in</code>: Starts the animation slowly with a gradual increase in speed. It is equivalent to <code>cubic-bezier(0.42, 0, 1, 1)</code>.</li>
<li><code>ease-out</code>: Starts fast and ends the animation slowly. It is equivalent to <code>cubic-bezier(0, 0, 0.58, 1)</code>.</li>
<li><code>ease-in-out</code>: Starts and ends the animation slowly. It is equivalent to <code>cubic-bezier(0.42, 0, 0.58, 1)</code>.</li>
<li><code>linear</code>: Starts and ends the animation using a consistent speed throughout the animation's duration. It is equivalent to <code>cubic-bezier(0, 0, 1, 1)</code>.</li>
<li><code>cubic-bezier(p1, p2, p3, p4)</code>: Allows you to define the values of the <a target="_blank" href="https://www.cssportal.com/css-cubic-bezier-generator/">cubic-Bezier curve</a>.</li>
</ul>
<p>Let's see some examples of the <code>animation-timing-function</code> property.</p>
<h4 id="heading-how-to-animate-an-elements-width-change-using-a-linear-speed">How to animate an element's width change using a linear speed</h4>
<pre><code class="lang-css"><span class="hljs-selector-tag">div</span> {
  <span class="hljs-attribute">width</span>: <span class="hljs-number">150px</span>;
  <span class="hljs-attribute">height</span>: <span class="hljs-number">150px</span>;
  <span class="hljs-attribute">background-color</span>: purple;
  <span class="hljs-attribute">animation-name</span>: change-width;
  <span class="hljs-attribute">animation-duration</span>: <span class="hljs-number">7s</span>;
  <span class="hljs-attribute">animation-timing-function</span>: linear;
}

<span class="hljs-keyword">@keyframes</span> change-width {
  <span class="hljs-selector-tag">from</span> {<span class="hljs-attribute">width</span>: <span class="hljs-number">50px</span>;}
  <span class="hljs-selector-tag">to</span> {<span class="hljs-attribute">width</span>: <span class="hljs-number">100%</span>;}
}
</code></pre>
<p><a target="_blank" href="https://codesweetly.com/try-it-sdk/css/css-animations/js-tzwrdc"><strong>Try Editing It</strong></a></p>
<p>Here's what we did in the snippet above:</p>
<ol>
<li>The <code>animation-name</code> property specifies the <code>@keyframes</code> we wish to apply to the <code>div</code> element.</li>
<li>The <code>animation-duration</code> property sets the animation's runtime for one cycle to seven seconds (<code>7s</code>).</li>
<li>The <code>linear</code> timing function applied a consistent speed to the <code>div</code>'s animation.</li>
<li>We created <code>change-width</code>'s @keyframes ruleset.</li>
<li>We defined two keyframes for browsers to apply when the <code>div</code>'s animation is at zero percent (<code>0%</code>) and one hundred percent (<code>100%</code>) duration.</li>
</ol>
<p>Therefore, browsers will create a smooth seven-second animation from <code>change-width</code>'s first keyframe to its last.</p>
<p>Let's see another example.</p>
<h4 id="heading-how-to-animate-an-elements-width-change-using-an-ease-in-out-and-a-linear-speed">How to animate an element's width change using an ease-in-out and a linear speed</h4>
<pre><code class="lang-css"><span class="hljs-selector-tag">div</span> {
  <span class="hljs-attribute">width</span>: <span class="hljs-number">150px</span>;
  <span class="hljs-attribute">height</span>: <span class="hljs-number">150px</span>;
  <span class="hljs-attribute">color</span>: white;
  <span class="hljs-attribute">animation-name</span>: change-width;
  <span class="hljs-attribute">animation-duration</span>: <span class="hljs-number">7s</span>;
}

<span class="hljs-selector-class">.first-div</span> {
  <span class="hljs-attribute">background-color</span>: purple;
  <span class="hljs-attribute">animation-timing-function</span>: ease-in-out;
}

<span class="hljs-selector-class">.second-div</span> {
  <span class="hljs-attribute">background-color</span>: orange;
  <span class="hljs-attribute">animation-timing-function</span>: linear;
}

<span class="hljs-keyword">@keyframes</span> change-width {
  <span class="hljs-selector-tag">from</span> {<span class="hljs-attribute">width</span>: <span class="hljs-number">50px</span>;}
  <span class="hljs-selector-tag">to</span> {<span class="hljs-attribute">width</span>: <span class="hljs-number">100%</span>;}
}
</code></pre>
<p><a target="_blank" href="https://codesweetly.com/try-it-sdk/css/css-animations/js-janmqa"><strong>Try Editing It</strong></a></p>
<p>Here's what we did in the snippet above:</p>
<ol>
<li>The <code>animation-name</code> property specifies the <code>@keyframes</code> we wish to apply to the <code>div</code> element.</li>
<li>The <code>animation-duration</code> property sets the animation's runtime for one cycle to seven seconds (<code>7s</code>).</li>
<li>We used the <code>ease-in-out</code> timing function to apply a slow start and slow end speed to the <code>first-div</code>'s animation.</li>
<li>The <code>linear</code> timing function applied a consistent speed to the <code>second-div</code>'s animation.</li>
<li>We created <code>change-width</code>'s @keyframes ruleset.</li>
<li>We defined two keyframes for browsers to apply when the <code>div</code> elements' animations are at their zero percent (<code>0%</code>) and one hundred percent (<code>100%</code>) durations.</li>
</ol>
<p>Therefore, browsers will create a smooth seven-second animation from <code>change-width</code>'s first keyframe to its last.</p>
<h3 id="heading-what-is-the-css-animation-delay-property">What is the CSS <code>animation-delay</code> property?</h3>
<p>The CSS <code>animation-delay</code> property defines how long browsers should wait before starting an animation.</p>
<p>In other words, use <code>animation-delay</code> to specify whether the animation should start immediately from the beginning, immediately from a specific time, or later (after some delay).</p>
<p><strong>Note the following:</strong></p>
<ul>
<li>The <code>animation-delay</code> property must be in milliseconds (ms) or seconds (s) units.</li>
<li><code>0s</code> is <code>animation-delay</code>'s default value. It causes the animation to start once browsers apply it to an HTML element.</li>
<li>A negative value causes the animation to start immediately from the specified time. For instance, suppose an element's <code>animation-delay</code> value is <code>-3s</code>. In that case, the animation will begin immediately at 3 seconds.</li>
<li>A positive value causes the animation to start after the specified delay time has elapsed. For instance, suppose an element's <code>animation-delay</code> value is <code>3s</code>. In that case, the animation will begin after a 3-second delay.</li>
</ul>
<p>Let's see some examples of the <code>animation-delay</code> property.</p>
<h4 id="heading-how-to-animate-an-elements-width-change-with-a-four-second-delay">How to animate an element's width change with a four-second delay</h4>
<pre><code class="lang-css"><span class="hljs-selector-tag">div</span> {
  <span class="hljs-attribute">width</span>: <span class="hljs-number">150px</span>;
  <span class="hljs-attribute">height</span>: <span class="hljs-number">150px</span>;
  <span class="hljs-attribute">color</span>: white;
  <span class="hljs-attribute">animation-name</span>: change-width;
  <span class="hljs-attribute">animation-duration</span>: <span class="hljs-number">7s</span>;
}

<span class="hljs-selector-class">.first-div</span> {
  <span class="hljs-attribute">background-color</span>: purple;
  <span class="hljs-attribute">animation-timing-function</span>: ease-in-out;
}

<span class="hljs-selector-class">.second-div</span> {
  <span class="hljs-attribute">background-color</span>: orange;
  <span class="hljs-attribute">animation-timing-function</span>: linear;
  <span class="hljs-attribute">animation-delay</span>: <span class="hljs-number">4s</span>;
}

<span class="hljs-keyword">@keyframes</span> change-width {
  <span class="hljs-selector-tag">from</span> {<span class="hljs-attribute">width</span>: <span class="hljs-number">50px</span>;}
  <span class="hljs-selector-tag">to</span> {<span class="hljs-attribute">width</span>: <span class="hljs-number">100%</span>;}
}
</code></pre>
<p><a target="_blank" href="https://codesweetly.com/try-it-sdk/css/css-animations/js-iidpmk"><strong>Try Editing It</strong></a></p>
<p>Here's what we did in the snippet above:</p>
<ol>
<li>The <code>animation-name</code> property specifies the <code>@keyframes</code> we wish to apply to the <code>div</code> elements.</li>
<li>The <code>animation-duration</code> property sets the animation's runtime for one cycle to seven seconds (<code>7s</code>).</li>
<li>We used the <code>ease-in-out</code> timing function to apply a slow start and slow end speed to the <code>first-div</code>'s animation.</li>
<li>The <code>linear</code> timing function applied a consistent speed to the <code>second-div</code>'s animation.</li>
<li>The <code>animation-delay</code> property applied a four-second (<code>4s</code>) delay to the starting time of the <code>second-div</code>'s animation.</li>
<li>We created <code>change-width</code>'s @keyframes ruleset.</li>
<li>We defined two keyframes for browsers to apply when the <code>div</code> elements' animations are at their zero percent (<code>0%</code>) and one hundred percent (<code>100%</code>) durations.</li>
</ol>
<p>Therefore, browsers will delay the <code>second-div</code>'s animation for four seconds while starting the <code>first-div</code>'s animation immediately.</p>
<p>Below is another example of the <code>animation-delay</code> property.</p>
<h4 id="heading-how-to-animate-an-elements-width-change-from-the-fourth-second-mark-of-the-animation-sequence">How to animate an element's width change from the fourth-second mark of the animation sequence</h4>
<pre><code class="lang-css"><span class="hljs-selector-tag">div</span> {
  <span class="hljs-attribute">width</span>: <span class="hljs-number">150px</span>;
  <span class="hljs-attribute">height</span>: <span class="hljs-number">150px</span>;
  <span class="hljs-attribute">color</span>: white;
  <span class="hljs-attribute">animation-name</span>: change-width;
  <span class="hljs-attribute">animation-duration</span>: <span class="hljs-number">7s</span>;
}

<span class="hljs-selector-class">.first-div</span> {
  <span class="hljs-attribute">background-color</span>: purple;
  <span class="hljs-attribute">animation-timing-function</span>: ease-in-out;
}

<span class="hljs-selector-class">.second-div</span> {
  <span class="hljs-attribute">background-color</span>: orange;
  <span class="hljs-attribute">animation-timing-function</span>: linear;
  <span class="hljs-attribute">animation-delay</span>: -<span class="hljs-number">4s</span>;
}

<span class="hljs-keyword">@keyframes</span> change-width {
  <span class="hljs-selector-tag">from</span> {<span class="hljs-attribute">width</span>: <span class="hljs-number">50px</span>;}
  <span class="hljs-selector-tag">to</span> {<span class="hljs-attribute">width</span>: <span class="hljs-number">100%</span>;}
}
</code></pre>
<p><a target="_blank" href="https://codesweetly.com/try-it-sdk/css/css-animations/js-6xga4t"><strong>Try Editing It</strong></a></p>
<p>Here's what we did in the snippet above:</p>
<ol>
<li>The <code>animation-name</code> property specifies the <code>@keyframes</code> we wish to apply to the <code>div</code> elements.</li>
<li>The <code>animation-duration</code> property sets the animation's runtime for one cycle to seven seconds (<code>7s</code>).</li>
<li>We used the <code>ease-in-out</code> timing function to apply a slow start and slow end speed to the <code>first-div</code>'s animation.</li>
<li>The <code>linear</code> timing function applied a consistent speed to the <code>second-div</code>'s animation.</li>
<li>The <code>animation-delay</code> property makes the <code>second-div</code>'s animation start from the fourth-second mark of the animation sequence.</li>
<li>We created <code>change-width</code>'s @keyframes ruleset.</li>
<li>We defined two keyframes for browsers to apply when the <code>div</code> elements' animations are at their zero percent (<code>0%</code>) and one hundred percent (<code>100%</code>) durations.</li>
</ol>
<p>Therefore, browsers will start the <code>second-div</code>'s animation immediately at the fourth-second mark.</p>
<h3 id="heading-what-is-the-css-animation-iteration-count-property">What is the CSS <code>animation-iteration-count</code> property?</h3>
<p>The CSS <code>animation-iteration-count</code> property defines the number of times browsers should repeat an animation.</p>
<p><strong>Note the following:</strong></p>
<ul>
<li><code>1</code> is <code>animation-iteration-count</code>'s default value.</li>
<li>The <code>animation-iteration-count</code> property accepts non-integer values—for instance, <code>0.5</code> tells browsers to play half of a single animation cycle.</li>
<li><code>animation-iteration-count</code> does <em>not</em> accept negative values.</li>
<li>An <code>infinite</code> value means browsers should repeat the animation forever.</li>
</ul>
<p>Below are some examples.</p>
<h4 id="heading-how-to-animate-an-elements-width-change-with-a-two-cycle-iteration">How to animate an element's width change with a two-cycle iteration</h4>
<pre><code class="lang-css"><span class="hljs-selector-tag">div</span> {
  <span class="hljs-attribute">width</span>: <span class="hljs-number">70px</span>;
  <span class="hljs-attribute">height</span>: <span class="hljs-number">50px</span>;
  <span class="hljs-attribute">background-color</span>: purple;
  <span class="hljs-attribute">animation-name</span>: change-width;
  <span class="hljs-attribute">animation-duration</span>: <span class="hljs-number">5s</span>;
  <span class="hljs-attribute">animation-timing-function</span>: ease-in-out;
  <span class="hljs-attribute">animation-iteration-count</span>: <span class="hljs-number">2</span>;
}

<span class="hljs-keyword">@keyframes</span> change-width {
  <span class="hljs-selector-tag">from</span> {<span class="hljs-attribute">width</span>: <span class="hljs-number">70px</span>;}
  <span class="hljs-selector-tag">to</span> {<span class="hljs-attribute">width</span>: <span class="hljs-number">100%</span>;}
}
</code></pre>
<p><a target="_blank" href="https://codesweetly.com/try-it-sdk/css/css-animations/js-vbcswe"><strong>Try Editing It</strong></a></p>
<p>Here's what we did in the snippet above:</p>
<ol>
<li>The <code>animation-name</code> property specifies the <code>@keyframes</code> we wish to apply to the <code>div</code> element.</li>
<li>The <code>animation-duration</code> property sets the animation's runtime for one cycle to five seconds (<code>5s</code>).</li>
<li>We used the <code>ease-in-out</code> timing function to apply a slow start and slow end speed to the <code>div</code>'s animation.</li>
<li>The <code>animation-iteration-count</code> property tells browsers to run the animation twice.</li>
<li>We created <code>change-width</code>'s @keyframes ruleset.</li>
<li>We defined two keyframes for browsers to apply when the <code>div</code> element's animation is at zero percent (<code>0%</code>) and one hundred percent (<code>100%</code>) duration.</li>
</ol>
<p>Therefore, browsers will run the <code>div</code>'s animation in two cycles.</p>
<p>Below is another example of the <code>animation-iteration-count</code> property.</p>
<h4 id="heading-how-to-animate-an-elements-width-change-with-an-infinite-iteration">How to animate an element's width change with an infinite iteration</h4>
<pre><code class="lang-css"><span class="hljs-selector-tag">div</span> {
  <span class="hljs-attribute">width</span>: <span class="hljs-number">70px</span>;
  <span class="hljs-attribute">height</span>: <span class="hljs-number">50px</span>;
  <span class="hljs-attribute">animation-name</span>: change-width;
  <span class="hljs-attribute">animation-duration</span>: <span class="hljs-number">5s</span>;
  <span class="hljs-attribute">animation-timing-function</span>: ease-in-out;
  <span class="hljs-attribute">animation-iteration-count</span>: infinite;
}

<span class="hljs-keyword">@keyframes</span> change-width {
  <span class="hljs-selector-tag">from</span> {<span class="hljs-attribute">width</span>: <span class="hljs-number">70px</span>; <span class="hljs-attribute">background-color</span>: purple;}
  <span class="hljs-selector-tag">to</span> {<span class="hljs-attribute">width</span>: <span class="hljs-number">100%</span>; <span class="hljs-attribute">background-color</span>: orange;}
}
</code></pre>
<p><a target="_blank" href="https://codesweetly.com/try-it-sdk/css/css-animations/js-p1zwk5"><strong>Try Editing It</strong></a></p>
<p>Here's what we did in the snippet above:</p>
<ol>
<li>The <code>animation-name</code> property specifies the <code>@keyframes</code> we wish to apply to the <code>div</code> element.</li>
<li>The <code>animation-duration</code> property sets the animation's runtime for one cycle to five seconds (<code>5s</code>).</li>
<li>We used the <code>ease-in-out</code> timing function to apply a slow start and slow end speed to the <code>div</code>'s animation.</li>
<li>The <code>animation-iteration-count</code> property tells browsers to run the animation infinitely.</li>
<li>We created <code>change-width</code>'s @keyframes ruleset.</li>
<li>We defined two keyframes for browsers to apply when the <code>div</code> element's animation is at its zero percent (<code>0%</code>) and one hundred percent (<code>100%</code>) duration.</li>
</ol>
<p>Therefore, browsers will run the <code>div</code>'s animation infinitely.</p>
<h3 id="heading-what-is-the-css-animation-direction-property">What is the CSS <code>animation-direction</code> property?</h3>
<p>The CSS <code>animation-direction</code> property specifies whether the animation's first iteration should run forward or backward. It also defines whether browsers should alternate the direction of subsequent iterations.</p>
<p>The values <code>animation-direction</code> accepts are:</p>
<ul>
<li><code>normal</code>: Play the animation in the normal direction (that is, forward). <code>normal</code> is <code>animation-direction</code>'s default value.</li>
<li><code>reverse</code>: Play the animation in the reverse direction (backward).</li>
<li><code>alternate</code>: Play the first animation cycle in the normal direction. Then, alternates the subsequent iterations between the backward and forward directions.</li>
<li><code>alternate-reverse</code>: Play the first animation cycle in the reverse direction. Then, alternates the subsequent iterations between the forward and backward directions.</li>
</ul>
<p>Below are some examples.</p>
<h4 id="heading-how-to-animate-an-elements-width-change-while-starting-each-animation-cycle-backward">How to animate an element's width change while starting each animation cycle backward</h4>
<pre><code class="lang-css"><span class="hljs-selector-tag">div</span> {
  <span class="hljs-attribute">width</span>: <span class="hljs-number">70px</span>;
  <span class="hljs-attribute">height</span>: <span class="hljs-number">50px</span>;
  <span class="hljs-attribute">animation-name</span>: change-width;
  <span class="hljs-attribute">animation-duration</span>: <span class="hljs-number">5s</span>;
  <span class="hljs-attribute">animation-timing-function</span>: ease-in-out;
  <span class="hljs-attribute">animation-iteration-count</span>: infinite;
  <span class="hljs-attribute">animation-direction</span>: reverse;
}

<span class="hljs-keyword">@keyframes</span> change-width {
  <span class="hljs-selector-tag">from</span> {<span class="hljs-attribute">width</span>: <span class="hljs-number">70px</span>; <span class="hljs-attribute">background-color</span>: purple;}
  <span class="hljs-selector-tag">to</span> {<span class="hljs-attribute">width</span>: <span class="hljs-number">100%</span>; <span class="hljs-attribute">background-color</span>: orange;}
}
</code></pre>
<p><a target="_blank" href="https://codesweetly.com/try-it-sdk/css/css-animations/js-d2n3zt"><strong>Try Editing It</strong></a></p>
<p>Here's what we did in the snippet above:</p>
<ol>
<li>The <code>animation-name</code> property specifies the <code>@keyframes</code> we wish to apply to the <code>div</code> element.</li>
<li>The <code>animation-duration</code> property sets the animation's runtime for one cycle to five seconds (<code>5s</code>).</li>
<li>We used the <code>ease-in-out</code> timing function to apply a slow start and slow end speed to the <code>div</code>'s animation.</li>
<li>The <code>animation-iteration-count</code> property tells browsers to run the animation infinitely.</li>
<li>The <code>animation-direction</code> property starts each animation cycle in reverse (backward).</li>
<li>We created <code>change-width</code>'s @keyframes ruleset.</li>
<li>We defined two keyframes for browsers to apply when the <code>div</code> element's animation is at zero percent (<code>0%</code>) and one hundred percent (<code>100%</code>) duration.</li>
</ol>
<p>Below is another example of the <code>animation-direction</code> property.</p>
<h4 id="heading-how-to-animate-an-elements-width-change-while-alternating-the-animations-direction">How to animate an element's width change while alternating the animation's direction</h4>
<pre><code class="lang-css"><span class="hljs-selector-tag">div</span> {
  <span class="hljs-attribute">width</span>: <span class="hljs-number">70px</span>;
  <span class="hljs-attribute">height</span>: <span class="hljs-number">50px</span>;
  <span class="hljs-attribute">animation-name</span>: change-width;
  <span class="hljs-attribute">animation-duration</span>: <span class="hljs-number">5s</span>;
  <span class="hljs-attribute">animation-timing-function</span>: ease-in-out;
  <span class="hljs-attribute">animation-iteration-count</span>: infinite;
  <span class="hljs-attribute">animation-direction</span>: alternate;
}

<span class="hljs-keyword">@keyframes</span> change-width {
  <span class="hljs-selector-tag">from</span> {<span class="hljs-attribute">width</span>: <span class="hljs-number">70px</span>; <span class="hljs-attribute">background-color</span>: purple;}
  <span class="hljs-selector-tag">to</span> {<span class="hljs-attribute">width</span>: <span class="hljs-number">100%</span>; <span class="hljs-attribute">background-color</span>: orange;}
}
</code></pre>
<p><a target="_blank" href="https://codesweetly.com/try-it-sdk/css/css-animations/js-ld9kms"><strong>Try Editing It</strong></a></p>
<p>Here's what we did in the snippet above:</p>
<ol>
<li>The <code>animation-name</code> property specifies the <code>@keyframes</code> we wish to apply to the <code>div</code> element.</li>
<li>The <code>animation-duration</code> property sets the animation's runtime for one cycle to five seconds (<code>5s</code>).</li>
<li>We used the <code>ease-in-out</code> timing function to apply a slow start and slow end speed to the <code>div</code>'s animation.</li>
<li>The <code>animation-iteration-count</code> property tells browsers to run the animation infinitely.</li>
<li>The <code>animation-direction</code> property alternates the direction of each cycle's animation.</li>
<li>We created <code>change-width</code>'s @keyframes ruleset.</li>
<li>We defined two keyframes for browsers to apply when the <code>div</code> element's animation is at zero percent (<code>0%</code>) and one hundred percent (<code>100%</code>) duration.</li>
</ol>
<h3 id="heading-what-is-the-css-animation-play-state-property">What is the CSS <code>animation-play-state</code> property?</h3>
<p>The CSS <code>animation-play-state</code> property specifies whether the browser is running or has paused a specific animation.</p>
<p>The values the <code>animation-play-state</code> property accepts are:</p>
<ul>
<li><code>running</code>: Specifies that the browser is running the animation. <code>running</code> is <code>animation-play-state</code>'s default value.</li>
<li><code>paused</code>: Specifies that the browser has paused the animation.</li>
</ul>
<p><strong>Here's an example:</strong></p>
<pre><code class="lang-css"><span class="hljs-selector-tag">div</span> {
  <span class="hljs-attribute">width</span>: <span class="hljs-number">70px</span>;
  <span class="hljs-attribute">height</span>: <span class="hljs-number">50px</span>;
  <span class="hljs-attribute">animation-name</span>: change-width;
  <span class="hljs-attribute">animation-duration</span>: <span class="hljs-number">5s</span>;
  <span class="hljs-attribute">animation-timing-function</span>: ease-in-out;
  <span class="hljs-attribute">animation-iteration-count</span>: infinite;
  <span class="hljs-attribute">animation-direction</span>: alternate;
}

<span class="hljs-selector-tag">div</span><span class="hljs-selector-pseudo">:hover</span> {
  <span class="hljs-attribute">animation-play-state</span>: paused;
}

<span class="hljs-keyword">@keyframes</span> change-width {
  <span class="hljs-selector-tag">from</span> {<span class="hljs-attribute">width</span>: <span class="hljs-number">70px</span>; <span class="hljs-attribute">background-color</span>: purple;}
  <span class="hljs-selector-tag">to</span> {<span class="hljs-attribute">width</span>: <span class="hljs-number">100%</span>; <span class="hljs-attribute">background-color</span>: orange;}
}
</code></pre>
<p><a target="_blank" href="https://codesweetly.com/try-it-sdk/css/css-animations/js-kbommn"><strong>Try Editing It</strong></a></p>
<p>Here's what we did in the snippet above:</p>
<ol>
<li>The <code>animation-name</code> property specifies the <code>@keyframes</code> we wish to apply to the <code>div</code> element.</li>
<li>The <code>animation-duration</code> property sets the animation's runtime for one cycle to five seconds (<code>5s</code>).</li>
<li>We used the <code>ease-in-out</code> timing function to apply a slow start and slow end speed to the <code>div</code>'s animation.</li>
<li>The <code>animation-iteration-count</code> property tells browsers to run the animation infinitely.</li>
<li>The <code>animation-direction</code> property alternates the direction of each cycle's animation.</li>
<li>We used the <code>animation-play-state</code> on the <code>div</code>'s hover <a target="_blank" href="https://codesweetly.com/css-pseudo-selectors">pseudo-class</a> to pause the animation whenever users move their mouse over the <code>div</code> element.</li>
<li>We created <code>change-width</code>'s @keyframes ruleset.</li>
<li>We defined two keyframes for browsers to apply when the <code>div</code> element's animation is at zero percent (<code>0%</code>) and one hundred percent (<code>100%</code>) duration.</li>
</ol>
<h3 id="heading-what-is-the-css-animation-fill-mode-property">What is the CSS <code>animation-fill-mode</code> property?</h3>
<p>The CSS <code>animation-fill-mode</code> property defines the styles browsers should apply to an element before (or after) its animation runs.</p>
<p>The values the <code>animation-fill-mode</code> property accepts are:</p>
<ul>
<li><code>none</code>: Browsers will apply <em>no</em> style to the element before or after the animation runs. <code>none</code> is <code>animation-fill-mode</code>'s default value.</li>
<li><code>forwards</code>: The element will retain the last keyframe's style declarations when the animation ends. (Note: The <code>animation-direction</code> and <code>animation-iteration-count</code> properties determine the last keyframe.)</li>
<li><code>backwards</code>: The element will retain the first keyframe's style declarations during the <code>animation-delay</code> period. (Note: The <code>animation-direction</code> property determines the first keyframe.)</li>
<li><code>both</code>: Browsers will apply both the forwards and backwards rules. Therefore, the animation properties will extend in both directions.</li>
</ul>
<p>Below are some examples.</p>
<h4 id="heading-how-to-style-an-element-after-its-animation-ends">How to style an element after its animation ends</h4>
<pre><code class="lang-css"><span class="hljs-selector-tag">div</span> {
  <span class="hljs-attribute">width</span>: <span class="hljs-number">70px</span>;
  <span class="hljs-attribute">height</span>: <span class="hljs-number">50px</span>;
  <span class="hljs-attribute">background-color</span>: green;
  <span class="hljs-attribute">animation-name</span>: change-width;
  <span class="hljs-attribute">animation-duration</span>: <span class="hljs-number">5s</span>;
  <span class="hljs-attribute">animation-timing-function</span>: ease-in-out;
  <span class="hljs-attribute">animation-fill-mode</span>: forwards;
}

<span class="hljs-keyword">@keyframes</span> change-width {
  <span class="hljs-selector-tag">from</span> {<span class="hljs-attribute">width</span>: <span class="hljs-number">70px</span>; <span class="hljs-attribute">background-color</span>: purple;}
  <span class="hljs-selector-tag">to</span> {<span class="hljs-attribute">width</span>: <span class="hljs-number">100%</span>; <span class="hljs-attribute">background-color</span>: orange;}
}
</code></pre>
<p><a target="_blank" href="https://codesweetly.com/try-it-sdk/css/css-animations/js-lkc7mw"><strong>Try Editing It</strong></a></p>
<p>Here's what we did in the snippet above:</p>
<ol>
<li>The <code>animation-name</code> property specifies the <code>@keyframes</code> we wish to apply to the <code>div</code> element.</li>
<li>The <code>animation-duration</code> property sets the animation's runtime for one cycle to five seconds (<code>5s</code>).</li>
<li>We used the <code>ease-in-out</code> timing function to apply a slow start and slow end speed to the <code>div</code>'s animation.</li>
<li>The <code>animation-fill-mode</code> property tells browsers to retain the last keyframe's style declarations when the animation ends.</li>
<li>We created <code>change-width</code>'s @keyframes ruleset.</li>
<li>We defined two keyframes for browsers to apply when the <code>div</code> element's animation is at zero percent (<code>0%</code>) and one hundred percent (<code>100%</code>) duration.</li>
</ol>
<p>Below is another example of the <code>animation-fill-mode</code> property.</p>
<h4 id="heading-how-to-style-an-element-during-its-animation-delay-period">How to style an element during its animation delay period</h4>
<pre><code class="lang-css"><span class="hljs-selector-tag">div</span> {
  <span class="hljs-attribute">width</span>: <span class="hljs-number">70px</span>;
  <span class="hljs-attribute">height</span>: <span class="hljs-number">50px</span>;
  <span class="hljs-attribute">background-color</span>: green;
  <span class="hljs-attribute">animation-name</span>: change-width;
  <span class="hljs-attribute">animation-duration</span>: <span class="hljs-number">5s</span>;
  <span class="hljs-attribute">animation-timing-function</span>: ease-in-out;
  <span class="hljs-attribute">animation-delay</span>: <span class="hljs-number">3s</span>;
  <span class="hljs-attribute">animation-fill-mode</span>: backwards;
}

<span class="hljs-keyword">@keyframes</span> change-width {
  <span class="hljs-selector-tag">from</span> {<span class="hljs-attribute">width</span>: <span class="hljs-number">70px</span>; <span class="hljs-attribute">background-color</span>: purple;}
  <span class="hljs-selector-tag">to</span> {<span class="hljs-attribute">width</span>: <span class="hljs-number">100%</span>; <span class="hljs-attribute">background-color</span>: orange;}
}
</code></pre>
<p><a target="_blank" href="https://codesweetly.com/try-it-sdk/css/css-animations/js-nfmq3r"><strong>Try Editing It</strong></a></p>
<p>Here's what we did in the snippet above:</p>
<ol>
<li>The <code>animation-name</code> property specifies the <code>@keyframes</code> we wish to apply to the <code>div</code> element.</li>
<li>The <code>animation-duration</code> property sets the animation's runtime for one cycle to five seconds (<code>5s</code>).</li>
<li>We used the <code>ease-in-out</code> timing function to apply a slow start and slow end speed to the <code>div</code>'s animation.</li>
<li>The <code>animation-fill-mode</code> property tells browsers to retain the first keyframe's style declarations during the <code>animation-delay</code> period.</li>
<li>We created <code>change-width</code>'s @keyframes ruleset.</li>
<li>We defined two keyframes for browsers to apply when the <code>div</code> element's animation is at zero percent (<code>0%</code>) and one hundred percent (<code>100%</code>) duration.</li>
</ol>
<p>Let's see a third example of the <code>animation-fill-mode</code> property.</p>
<h4 id="heading-how-to-style-an-element-during-its-animation-delay-and-after-the-animation">How to style an element during its animation delay and after the animation</h4>
<pre><code class="lang-css"><span class="hljs-selector-tag">div</span> {
  <span class="hljs-attribute">width</span>: <span class="hljs-number">70px</span>;
  <span class="hljs-attribute">height</span>: <span class="hljs-number">50px</span>;
  <span class="hljs-attribute">background-color</span>: green;
  <span class="hljs-attribute">animation-name</span>: change-width;
  <span class="hljs-attribute">animation-duration</span>: <span class="hljs-number">5s</span>;
  <span class="hljs-attribute">animation-timing-function</span>: ease-in-out;
  <span class="hljs-attribute">animation-delay</span>: <span class="hljs-number">3s</span>;
  <span class="hljs-attribute">animation-fill-mode</span>: both;
}

<span class="hljs-keyword">@keyframes</span> change-width {
  <span class="hljs-selector-tag">from</span> {<span class="hljs-attribute">width</span>: <span class="hljs-number">70px</span>; <span class="hljs-attribute">background-color</span>: purple;}
  <span class="hljs-selector-tag">to</span> {<span class="hljs-attribute">width</span>: <span class="hljs-number">100%</span>; <span class="hljs-attribute">background-color</span>: orange;}
}
</code></pre>
<p><a target="_blank" href="https://codesweetly.com/try-it-sdk/css/css-animations/js-gbypmt"><strong>Try Editing It</strong></a></p>
<p>Here's what we did in the snippet above:</p>
<ol>
<li>The <code>animation-name</code> property specifies the <code>@keyframes</code> we wish to apply to the <code>div</code> element.</li>
<li>The <code>animation-duration</code> property sets the animation's runtime for one cycle to five seconds (<code>5s</code>).</li>
<li>We used the <code>ease-in-out</code> timing function to apply a slow start and slow end speed to the <code>div</code>'s animation.</li>
<li>The <code>animation-fill-mode</code> property tells browsers to apply both the forwards and backwards rules.</li>
<li>We created <code>change-width</code>'s @keyframes ruleset.</li>
<li>We defined two keyframes for browsers to use when the <code>div</code> element's animation is at zero percent (<code>0%</code>) and one hundred percent (<code>100%</code>) duration.</li>
</ol>
<h2 id="heading-what-is-the-css-animation-property">What is the CSS <code>animation</code> Property?</h2>
<p>We use the <code>animation</code> property as a shorthand for:</p>
<ul>
<li><code>animation-name</code></li>
<li><code>animation-duration</code></li>
<li><code>animation-timing-function</code></li>
<li><code>animation-delay</code></li>
<li><code>animation-iteration-count</code></li>
<li><code>animation-direction</code></li>
<li><code>animation-play-state</code></li>
<li><code>animation-fill-mode</code></li>
</ul>
<p>In other words, instead of writing:</p>
<pre><code class="lang-css"><span class="hljs-selector-tag">div</span> {
  <span class="hljs-attribute">animation-name</span>: change-width;
  <span class="hljs-attribute">animation-duration</span>: <span class="hljs-number">5s</span>;
  <span class="hljs-attribute">animation-timing-function</span>: ease-in-out;
  <span class="hljs-attribute">animation-delay</span>: <span class="hljs-number">2s</span>;
  <span class="hljs-attribute">animation-iteration-count</span>: <span class="hljs-number">3</span>;
  <span class="hljs-attribute">animation-direction</span>: alternate;
  <span class="hljs-attribute">animation-play-state</span>: running;
  <span class="hljs-attribute">animation-fill-mode</span>: both;
}
</code></pre>
<p>You can alternatively use the <code>animation</code> property to shorten your code like so:</p>
<pre><code class="lang-css"><span class="hljs-selector-tag">div</span> {
  <span class="hljs-attribute">animation</span>: <span class="hljs-number">5s</span> ease-in-out <span class="hljs-number">2s</span> <span class="hljs-number">3</span> alternate both running change-width;
}
</code></pre>
<p><a target="_blank" href="https://codesweetly.com/try-it-sdk/css/css-animations/js-37ccew"><strong>Try Editing It</strong></a></p>
<p>Here is the <code>animation</code> property's syntax:</p>
<pre><code class="lang-css"><span class="hljs-selector-tag">animation</span>: <span class="hljs-selector-tag">animation-duration</span> <span class="hljs-selector-tag">animation-timing-function</span> <span class="hljs-selector-tag">animation-delay</span> <span class="hljs-selector-tag">animation-iteration-count</span> <span class="hljs-selector-tag">animation-direction</span> <span class="hljs-selector-tag">animation-fill-mode</span> <span class="hljs-selector-tag">animation-play-state</span> <span class="hljs-selector-tag">animation-name</span>;
</code></pre>
<p><strong>Note:</strong></p>
<ul>
<li>The way you arrange the time values is essential. Browsers read the first time-value as <code>animation-duration</code>. And they assign the second one to <code>animation-delay</code>.</li>
<li>It is best to list <code>animation-name</code> last. Otherwise, browsers may assign the <code>animation-name</code>'s value to other properties.</li>
<li>You can apply multiple <code>@keyframes</code> <a target="_blank" href="https://codesweetly.com/css-ruleset">rulesets</a> to an element using the <code>animation</code> property. Here's an example:</li>
</ul>
<pre><code class="lang-css"><span class="hljs-selector-tag">div</span> {
  <span class="hljs-attribute">width</span>: <span class="hljs-number">70px</span>;
  <span class="hljs-attribute">height</span>: <span class="hljs-number">70px</span>;
  <span class="hljs-attribute">background-color</span>: green;
  <span class="hljs-attribute">animation</span>: 
    <span class="hljs-number">5s</span> ease-in-out <span class="hljs-number">3s</span> <span class="hljs-number">3</span> alternate both change-width, 
    <span class="hljs-number">5s</span> <span class="hljs-number">3s</span> infinite alternate both change-shape, 
    <span class="hljs-number">5s</span> <span class="hljs-number">3s</span> infinite rotate-hue;
}

<span class="hljs-keyword">@keyframes</span> change-width {
  <span class="hljs-selector-tag">from</span> {<span class="hljs-attribute">width</span>: <span class="hljs-number">70px</span>; <span class="hljs-attribute">background-color</span>: purple;}
  <span class="hljs-selector-tag">to</span> {<span class="hljs-attribute">width</span>: <span class="hljs-number">100%</span>; <span class="hljs-attribute">background-color</span>: orange;}
}

<span class="hljs-keyword">@keyframes</span> change-shape {
  <span class="hljs-selector-tag">from</span> {<span class="hljs-attribute">border-radius</span>: <span class="hljs-number">0%</span>; <span class="hljs-attribute">border</span>: <span class="hljs-number">1px</span> solid blue;}
  <span class="hljs-selector-tag">to</span> {<span class="hljs-attribute">border-radius</span>: <span class="hljs-number">50%</span>; <span class="hljs-attribute">border</span>: <span class="hljs-number">7px</span> solid green;}
}

<span class="hljs-keyword">@keyframes</span> rotate-hue {
  <span class="hljs-selector-tag">from</span> {<span class="hljs-attribute">filter</span>: <span class="hljs-built_in">hue-rotate</span>(<span class="hljs-number">0deg</span>);}
  <span class="hljs-selector-tag">to</span> {<span class="hljs-attribute">filter</span>: <span class="hljs-built_in">hue-rotate</span>(<span class="hljs-number">360deg</span>);}
}
</code></pre>
<p><a target="_blank" href="https://codesweetly.com/try-it-sdk/css/css-animations/js-4lyg4d"><strong>Try Editing It</strong></a></p>
<p>The snippet above applied three <code>@keyframes</code> rulesets to the <code>div</code> element using commas (<code>,</code>) to separate each <code>@keyframes</code>' configurations.</p>
<p><strong>Note:</strong> We used the <a target="_blank" href="https://www.quackit.com/css/functions/css_hue-rotate_function.cfm"><code>hue-rotate()</code></a> function to rotate the <code>div</code>'s colors.</p>
<h2 id="heading-important-stuff-to-know-about-css-transitions-and-animations">Important Stuff to Know about CSS Transitions and Animations</h2>
<ol>
<li>You can't animate all CSS properties. Have a look at MDN's <a target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_animated_properties">Animatable CSS properties</a> article to see the ones you can animate.</li>
<li>CSS transitions and animations are <a target="_blank" href="https://codesweetly.com/web-tech-terms-e#expensive-operation-computing">expensive operations</a> for most CSS properties—except <code>opacity</code> and <code>transform</code>. In other words, applying transitions (or animations) to any CSS box model property is inherently a <a target="_blank" href="https://codesweetly.com/web-tech-terms-c#cpu-intensive">CPU-intensive</a> task. Therefore, animate only <code>opacity</code>, and <code>transform</code> properties if you are concerned about your page's performance.</li>
<li>Be mindful of the <a target="_blank" href="https://dzhavat.github.io/2021/02/18/debugging-layout-repaint-issues-triggered-by-css-transition.html">layout repainting issues</a> that CSS transitions may cause through your elements' stacking order.</li>
</ol>
<h2 id="heading-wrapping-up">Wrapping up</h2>
<p>In this article, we discuss the differences between CSS transitions and animations. We also used examples to discuss how to use them.</p>
<p>Thanks for reading.</p>
<h3 id="heading-and-heres-a-useful-react-typescript-resource">And here's a useful React TypeScript resource:</h3>
<p>I wrote a book about <a target="_blank" href="https://amzn.to/3Pa4bI4">Creating NPM Packages</a>!</p>
<p>It is a beginner-friendly book that takes you from zero to creating, testing, and publishing NPM packages like a pro.</p>
<p><a target="_blank" href="https://amzn.to/3Pa4bI4"><img src="https://www.freecodecamp.org/news/content/images/2023/09/creating-npm-package-banner-codesweetly.png" alt="Creating NPM Package Book Now Available at Amazon" width="600" height="400" loading="lazy"></a></p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Create Animated Bubbles with HTML5 Canvas and JavaScript ]]>
                </title>
                <description>
                    <![CDATA[ Hello everyone! Welcome to this tutorial where we're going to dive into the world of creating fun bubbles in code using HTML canvas and JavaScript. The best part? We'll achieve all of this using just a touch of HTML and all JavaScript, no CSS. What w... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-create-animated-bubbles-with-html5-canvas-and-javascript/</link>
                <guid isPermaLink="false">66b99cdfbe5923657131acf1</guid>
                
                    <category>
                        <![CDATA[ animation ]]>
                    </category>
                
                    <category>
                        <![CDATA[ HTML5 ]]>
                    </category>
                
                    <category>
                        <![CDATA[ JavaScript ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Shruti Kapoor ]]>
                </dc:creator>
                <pubDate>Tue, 05 Sep 2023 14:08:02 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2023/08/shrutikapoor.dev--11-.jpg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Hello everyone! Welcome to this tutorial where we're going to dive into the world of creating fun bubbles in code using HTML canvas and JavaScript. The best part? We'll achieve all of this using just a touch of HTML and all JavaScript, no CSS.</p>
<h2 id="heading-what-we-will-learn">What we will learn</h2>
<p>In this article, you're going to master the following concepts:</p>
<ul>
<li>How to create circles using the <code>arc</code> method of the canvas context.</li>
<li>How to utilize the <code>requestAnimationFrame</code> function for smooth circle animations.</li>
<li>How to harness the power of JavaScript classes to create multiple circles without repeating code.</li>
<li>How to add stroke styles and fill styles to your circles for a 3D bubble effect.</li>
</ul>
<p>You can follow along with me, or use <a target="_blank" href="https://codepen.io/shrutikapoor08/pen/wvQXMVO">the final codepen</a> if you want to take a look at the source code.</p>
<p>If you prefer to learn in a video format, follow along this video:</p>
<div class="embed-wrapper">
        <iframe width="560" height="315" src="https://www.youtube.com/embed/IjPgXP3gDyI" style="aspect-ratio: 16 / 9; width: 100%; height: auto;" title="YouTube video player" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen="" loading="lazy"></iframe></div>
<h2 id="heading-getting-started">Getting Started</h2>
<p>First things first, we need an HTML5 Canvas element. Canvas is a powerful element for creating shapes, images and graphics. This is what we'll use for creating the bubbles.</p>
<p>Let’s set it up:</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">canvas</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"canvas"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">canvas</span>&gt;</span>
</code></pre>
<p>In order to do anything meaningful with canvas, we need to have access to it’s <code>context</code>. <a target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D">Context</a> provides an interface to render objects on the canvas and draw shapes.</p>
<p>Here's how to get access to canvas and it's context.</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> canvas = <span class="hljs-built_in">document</span>.getElementById(<span class="hljs-string">'canvas'</span>);
<span class="hljs-keyword">const</span> context = canvas.getContext(<span class="hljs-string">'2d'</span>);
</code></pre>
<p>We'll also set up our canvas to use the entire window height and width:</p>
<pre><code class="lang-js">canvas.width = <span class="hljs-built_in">window</span>.innerWidth;
canvas.height = <span class="hljs-built_in">window</span>.innerHeight;
</code></pre>
<p>Next, we'll give it canvas a nice soothing light blue background by adding some css. This is the only CSS we're going to use. You can also do this with JavaScript if you wish.</p>
<pre><code class="lang-css"><span class="hljs-selector-id">#canvas</span> {
  <span class="hljs-attribute">background</span>: <span class="hljs-number">#00b4ff</span>;
}
</code></pre>
<h2 id="heading-how-to-create-bubbles-with-canvas">How to Create Bubbles with Canvas</h2>
<p>Let’s get to the fun part. We're going to create bubbles by clicking on the canvas. To achieve this, we'll start by creating a click event handler:</p>
<pre><code class="lang-js">canvas.addEventListener(<span class="hljs-string">'click'</span>, handleDrawCircle);
</code></pre>
<p>Since we need to know where we clicked on our canvas, we are going to keep track of it in our <code>handleDrawCircle</code> function and use the event’s coordinates:</p>
<pre><code class="lang-js">
<span class="hljs-comment">//We are adding x and y here because we will need it later.</span>
<span class="hljs-keyword">let</span> x, y
<span class="hljs-keyword">const</span> handleDrawCircle = <span class="hljs-function">(<span class="hljs-params">event</span>) =&gt;</span> {
  x = event.pageX;
  y = event.pageY;

  <span class="hljs-comment">// Draw a bubble!</span>
  drawCircle(x, y);
};
</code></pre>
<h3 id="heading-how-to-draw-circles-using-the-arc-method">How to Draw Circles Using the <code>arc</code> Method</h3>
<p>To create circles, we're going to utilize the <a target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/arc"><code>arc</code> method available on canvas’s context.</a> The <code>arc</code> method accepts <code>x</code> and <code>y</code> (the center of the circle), a radius, and a start angle and end angle which for us will be <code>0</code> and <code>2* Math.PI</code> respectively because we're creating a full circle.</p>
<p>That is:</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> drawCircle = <span class="hljs-function">(<span class="hljs-params">x, y</span>) =&gt;</span> {
  context.beginPath();
  context.arc(x, y, <span class="hljs-number">50</span>, <span class="hljs-number">0</span>, <span class="hljs-number">2</span> * <span class="hljs-built_in">Math</span>.PI);

  context.strokeStyle = <span class="hljs-string">'white'</span>;
  context.stroke();
};
</code></pre>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/1zrbq3gcpff40nbvzbt8.png" alt="Drawing circles" width="1118" height="912" loading="lazy">
<em>circles created using the arc method</em></p>
<h3 id="heading-how-to-move-circles-using-the-requestanimationframe-method">How to Move Circles Using the <code>requestAnimationFrame</code> Method</h3>
<p>Now that we have circles, let's make them move because...</p>
<p><img src="https://media.giphy.com/media/ptS6CV6Ty7Dt26k6wq/giphy.gif" alt="A scene from the &quot;I like to move it&quot; song from the movie -Madagascar" width="480" height="270" loading="lazy"></p>
<p>Remember that when we created a circle, we used the <code>arc</code> method which accepted <code>x</code> and <code>y</code> coordinates — the center of the circle. If we move the <code>x</code> and <code>y</code> coordinate of our circle really fast, it will give an impression that the circles are moving. Let’s try that!</p>
<pre><code class="lang-js"><span class="hljs-comment">//Define a speed by which to increment to the x and y coordinates</span>

<span class="hljs-keyword">const</span> dx = <span class="hljs-built_in">Math</span>.random() * <span class="hljs-number">3</span>;
<span class="hljs-keyword">const</span> dy = <span class="hljs-built_in">Math</span>.random() * <span class="hljs-number">7</span>;

<span class="hljs-comment">//Incremenet the center of the circle with this speed</span>
x = x + dx;
y = y - dy;
</code></pre>
<p>We can move this inside a function:</p>
<pre><code class="lang-js"><span class="hljs-keyword">let</span> x, y;

<span class="hljs-keyword">const</span> move = <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-keyword">const</span> dx = <span class="hljs-built_in">Math</span>.random() * <span class="hljs-number">3</span>;
  <span class="hljs-keyword">const</span> dy = <span class="hljs-built_in">Math</span>.random() * <span class="hljs-number">7</span>;

  x = x + dx;
  y = y - dy;
};
</code></pre>
<p>To give our circle a seamless movement, we're going to create an <code>animate</code> function and use the browser's <code>requestAnimationFrame</code> method to create a moving circle:</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> animate = <span class="hljs-function">() =&gt;</span> {
  context.clearRect(<span class="hljs-number">0</span>, <span class="hljs-number">0</span>, canvas.width, canvas.height);

  move();
    drawCircle(x,y);

  requestAnimationFrame(animate);
};

<span class="hljs-comment">//Don't forget to call animate at the bottom </span>
animate();
</code></pre>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/z01uy7e82sqia06svu5t.gif" alt="Circle animating" width="571" height="622" loading="lazy">
<em>moving circles created with requestAnimationFrame method</em></p>
<h3 id="heading-how-to-create-particles-using-a-particle-class">How to Create Particles Using a Particle Class</h3>
<p>Now that we have created one circle, it’s time to create multiple circles! But before we do that, let's prepare our code.</p>
<p>In order to avoid repeating our code, we are going to use classes and introduce a <code>Particle</code> class. Particles are the building blocks of our dynamic artwork and animation. Each bubble is a particle with its own position, size, movement, and color attributes. Let's define a <strong><code>Particle</code></strong> class to encapsulate these properties:</p>
<pre><code class="lang-js"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Particle</span> </span>{
  <span class="hljs-keyword">constructor</span>(x = 0, y = 0) {}

  draw() {
    <span class="hljs-comment">// Drawing the particle as a colored circle</span>
    <span class="hljs-comment">// ...</span>
  }

  move() {
    <span class="hljs-comment">// Implementing particle movement</span>
    <span class="hljs-comment">// ...</span>
  }
}
</code></pre>
<p>Let’s move some of the constants we had set up to the <code>Particle</code> class:</p>
<pre><code class="lang-js"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Particle</span> </span>{
  <span class="hljs-keyword">constructor</span>(x = 0, y = 0) {
    <span class="hljs-built_in">this</span>.x = x;
    <span class="hljs-built_in">this</span>.y = y;
    <span class="hljs-built_in">this</span>.radius = <span class="hljs-built_in">Math</span>.random() * <span class="hljs-number">50</span>;
    <span class="hljs-built_in">this</span>.dx = <span class="hljs-built_in">Math</span>.random() * <span class="hljs-number">3</span>;
    <span class="hljs-built_in">this</span>.dy = <span class="hljs-built_in">Math</span>.random() * <span class="hljs-number">7</span>;
  }

  draw() {
    <span class="hljs-comment">// Drawing the particle as a colored circle</span>
    <span class="hljs-comment">// ...</span>
  }

  move() {
    <span class="hljs-comment">// Implementing particle movement</span>
    <span class="hljs-comment">// ...</span>
  }
}
</code></pre>
<p>The <strong><code>draw</code></strong> method will be responsible for rendering the particle on the canvas. We have already implemented this functionality in <code>drawCircle</code>, so let’s move it in our class and update the variables to be class variables:</p>
<pre><code class="lang-js"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Particle</span> </span>{
  <span class="hljs-keyword">constructor</span>(x = 0, y = 0) {
    <span class="hljs-built_in">this</span>.x = x;
    <span class="hljs-built_in">this</span>.y = y;
    <span class="hljs-built_in">this</span>.radius = <span class="hljs-built_in">Math</span>.random() * <span class="hljs-number">50</span>;
    <span class="hljs-built_in">this</span>.dx = <span class="hljs-built_in">Math</span>.random() * <span class="hljs-number">3</span>;
    <span class="hljs-built_in">this</span>.dy = <span class="hljs-built_in">Math</span>.random() * <span class="hljs-number">7</span>;
    <span class="hljs-built_in">this</span>.color = <span class="hljs-string">'white'</span>;
  }

  draw() {
    context.beginPath();
    context.arc(<span class="hljs-built_in">this</span>.x, <span class="hljs-built_in">this</span>.y, <span class="hljs-built_in">this</span>.radius, <span class="hljs-number">0</span>, <span class="hljs-number">2</span> * <span class="hljs-built_in">Math</span>.PI);
    context.strokeStyle = <span class="hljs-built_in">this</span>.color;
    context.stroke();

    context.fillStyle = <span class="hljs-built_in">this</span>.color;
    context.fill();
  }

  move() {}
}
</code></pre>
<p>Similarly, let’s move the <code>move</code> function within the class:</p>
<pre><code class="lang-js">move() {
    <span class="hljs-built_in">this</span>.x = <span class="hljs-built_in">this</span>.x + <span class="hljs-built_in">this</span>.dx;
    <span class="hljs-built_in">this</span>.y = <span class="hljs-built_in">this</span>.y - <span class="hljs-built_in">this</span>.dy;
}
</code></pre>
<p>Next, we need to make sure that we are calling the <code>Particle</code> class in our event handler:</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> handleDrawCircle = <span class="hljs-function">(<span class="hljs-params">event</span>) =&gt;</span> {
  <span class="hljs-keyword">const</span> x = event.pageX;
  <span class="hljs-keyword">const</span> y = event.pageY;

  <span class="hljs-keyword">const</span> particle = <span class="hljs-keyword">new</span> Particle(x, y);
};

canvas.addEventListener(<span class="hljs-string">'click'</span>, handleDrawCircle);
</code></pre>
<p>Since we need to access this particle in our animate function in order to call the <code>move</code> method on it, we'll store this particle in an array called <code>particleArray</code>. This array will also be helpful when creating lots of particles. </p>
<p>Here’s the updated code to reflect this:</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> particleArray = [];

<span class="hljs-keyword">const</span> handleDrawCircle = <span class="hljs-function">(<span class="hljs-params">event</span>) =&gt;</span> {
  <span class="hljs-keyword">const</span> x = event.pageX;
  <span class="hljs-keyword">const</span> y = event.pageY;

  <span class="hljs-keyword">const</span> particle = <span class="hljs-keyword">new</span> Particle(x, y);
  particleArray.push(particle);
};

canvas.addEventListener(<span class="hljs-string">'click'</span>, handleDrawCircle);
</code></pre>
<p>Remember to update the <code>animate</code> function too:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> animate = <span class="hljs-function">() =&gt;</span> {
    context.clearRect(<span class="hljs-number">0</span>, <span class="hljs-number">0</span>, canvas.width, canvas.height);

    particleArray.forEach(<span class="hljs-function">(<span class="hljs-params">particle</span>) =&gt;</span> {
        particle?.move();
        particle?.draw();
    });

    requestAnimationFrame(animate);
};
</code></pre>
<p>At this point, you will see these particles on your screen:</p>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/92rs6a5i1xn4v2gzdv8o.gif" alt="Multiple circles moving" width="624" height="464" loading="lazy"></p>
<p>Awesome! Now, to the fun part! Let's creates lots of circles and style them to make them look like bubbles.</p>
<p>To create lots of bubbles, we are going to create particles using a <code>for</code> loop and add them to the <code>particleArray</code> we had created.</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> handleDrawCircle = <span class="hljs-function">(<span class="hljs-params">event</span>) =&gt;</span> {
  <span class="hljs-keyword">const</span> x = event.pageX;
  <span class="hljs-keyword">const</span> y = event.pageY;

  <span class="hljs-keyword">for</span> (<span class="hljs-keyword">let</span> i = <span class="hljs-number">0</span>; i &lt; <span class="hljs-number">50</span>; i++) {
    <span class="hljs-keyword">const</span> particle = <span class="hljs-keyword">new</span> Particle(x, y);
    particleArray.push(particle);
  }
};

canvas.addEventListener(<span class="hljs-string">'click'</span>, handleDrawCircle);
</code></pre>
<p>In the animate function, we'll continuously update the canvas by clearing it and redrawing the particles in their new positions. This will give an illusion of the circle moving:</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> animate = <span class="hljs-function">() =&gt;</span> {
  context.clearRect(<span class="hljs-number">0</span>, <span class="hljs-number">0</span>, canvas.width, canvas.height);

  particleArray.forEach(<span class="hljs-function">(<span class="hljs-params">particle</span>) =&gt;</span> {
    particle?.move();
    particle?.draw();
  });

  requestAnimationFrame(animate);
};

animate();
</code></pre>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ya5u8w8qetqkcy2nbowe.gif" alt="Multiple circles animating" width="694" height="616" loading="lazy"></p>
<p>Now that we have bubbles moving, it’s time to add color to them to make them look like actual bubbles!</p>
<p>We will do this by adding a gradient fill to the bubbles. This can be done using the <code>context.createRadialGradient</code> method:</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> gradient = context.createRadialGradient(
  <span class="hljs-built_in">this</span>.x,
  <span class="hljs-built_in">this</span>.y,
  <span class="hljs-number">1</span>,
  <span class="hljs-built_in">this</span>.x + <span class="hljs-number">0.5</span>,
  <span class="hljs-built_in">this</span>.y + <span class="hljs-number">0.5</span>,
  <span class="hljs-built_in">this</span>.radius
);

gradient.addColorStop(<span class="hljs-number">0.3</span>, <span class="hljs-string">'rgba(255, 255, 255, 0.3)'</span>);
gradient.addColorStop(<span class="hljs-number">0.95</span>, <span class="hljs-string">'#e7feff'</span>);

context.fillStyle = gradient;
</code></pre>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/l80yde62l9mw3ceh1f1i.gif" alt="Bubbles" width="934" height="711" loading="lazy"></p>
<p><a target="_blank" href="https://codepen.io/shrutikapoor08/pen/wvQXMVO">Here’s the final codepen</a> if you want to take a look at the source code.</p>
<h2 id="heading-wrap-up">Wrap Up</h2>
<p>Congratulations! You've just created something super fun using only HTML Canvas and JavaScript. You've learned how to use the <code>arc</code> method, how to leverage the <code>requestAnimationFrame</code> method, how to harness the power of JavaScript classes, and how to style your bubbles using gradients for the 3D bubble effect.</p>
<p>Feel free to experiment with colors, speeds, and sizes to make your animations truly unique.</p>
<p>I hope you had as much fun following this tutorial as I did creating it. Now, it's your turn to experiment. I would love to see if you tried this out and what you created. Share with me your code link and I would love to check it out.</p>
<hr>
<p>And now a #DevJoke:</p>
<p>Question - Who won the debate for the best name for loop variable?</p>
<p>Answer - i won.</p>
<hr>
<p>If you enjoyed this article, share it with someone who will benefit from it. </p>
<p>If you are interested in articles like this and front-end articles on JavaScript, React, GraphQL or Accessibility and career advice from a Staff Engineer, <a target="_blank" href="https://tinyletter.com/shrutikapoor">sign up for my newsletter</a> and get these directly in your inbox.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Build an Image Carousel with React and Framer Motion ]]>
                </title>
                <description>
                    <![CDATA[ You've probably come across carousels in many modern-day applications. Known by various names such as sliders or rotators, these versatile web elements showcase content in a visually appealing, sliding, or rotating manner.  Carousels can help you sav... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/build-an-image-carousel-with-react-and-framer-motion/</link>
                <guid isPermaLink="false">66bc4c55a37e8c5876cb4d67</guid>
                
                    <category>
                        <![CDATA[ animation ]]>
                    </category>
                
                    <category>
                        <![CDATA[ React ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Clinton Joy ]]>
                </dc:creator>
                <pubDate>Mon, 03 Jul 2023 09:47:00 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2023/06/Screenshot-2023-06-26-at-10.45.34.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>You've probably come across carousels in many modern-day applications. Known by various names such as sliders or rotators, these versatile web elements showcase content in a visually appealing, sliding, or rotating manner. </p>
<p>Carousels can help you save space as well as enhance your User Interface and provide a great user experience.</p>
<p>Carousels have become a staple in UI design, often used to display images, testimonials, and more. They are indispensable when creating an engaging and dynamic interface.</p>
<p>In this article, we'll dive into the process of building an image carousel using React and Framer Motion, guiding you through every step to create a stunning and interactive visual component for your application.</p>
<h2 id="heading-what-is-framer-motion">What is Framer Motion?</h2>
<p>This is an open-source animation library for React applications that you can use to create dynamic and responsive animations for our web application.</p>
<p>Framer motion has several helpful features, including:</p>
<ol>
<li>Animation: This allows you to do seamless transitions for your components.</li>
<li>Gesture: It supports touch and mouse motions, which allows you to account for certain events.</li>
<li>Variants: Framer motion enables you to declare components declaratively, keeping your code organized and reusable.</li>
</ol>
<p>All these features are very useful and we will see them in action soon.</p>
<p>To gain a deeper understanding of Framer Motion, you can explore its <a target="_blank" href="https://www.framer.com/motion/">documentation and resources</a>. But for this article, we'll focus on the fundamentals. As I guide you through the basics of utilizing Framer Motion, my primary goal is to build an impressive and engaging image carousel.</p>
<h2 id="heading-how-to-set-up-your-development-environment">How to Set Up Your Development Environment</h2>
<p>The first thing we are gonna do is to set up your development Environment. This involves installing the necessary packages to successfully build your application. This includes installing <a target="_blank" href="https://nodejs.dev/en/download/">Node.js</a> and <a target="_blank" href="https://www.npmjs.com/package/download">npm</a></p>
<p>If you already have Node.js and npm installed, you don't need to download and install them again.</p>
<h3 id="heading-create-a-react-application">Create a React application</h3>
<p>At this point, I will assume you have Node and npm installed. To create a React application, simply go to your terminal and visit the directory you want your application to be in. Then run this command:</p>
<pre><code class="lang-js">npx create-react-app react-image-carousel
</code></pre>
<p>You can name your application whatever you want – but for the purpose of this article I will be calling it <code>react-image-carousel</code>.</p>
<p>When your React application is successfully created, open up your directory in your code editor. You should get some default files and styles and it should look something like this:</p>
<p><img src="https://i.imgur.com/rC9qt5N.png" alt="Image" width="1149" height="462" loading="lazy"></p>
<p>We won't need most of these files and styles for this project so you can clear up files like the: app.test.js, and logo.svg, and reportWebVitals.js,setupTest.js. You can also delete all the default styles in the App.css sheet.</p>
<p><img src="https://i.imgur.com/3en8Ssk.png" alt="Image" width="1032" height="359" loading="lazy"></p>
<p>Now that your React application is created and set up, the last step in setting up your development environment for this project is installing Framer motion. </p>
<p>To do this, simply go to your terminal make sure you are in the project directory and run this command:</p>
<pre><code class="lang-js"> npm  install framer-motion
</code></pre>
<p>and this should install the latest version of Framer Motion. Now you should be good to go. Simply use <code>npm run start</code> to fire the development server on your browser.</p>
<h2 id="heading-how-to-design-the-image-carousel-component">How to Design the Image Carousel Component</h2>
<p>To kick off the design we will first create a <code>Carousel.js</code> component. In the carousel component, we will import the <code>useState</code> hook from React and then the <code>motion</code> and <code>AnimatePresence</code> properties from Framer Motion.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> { useState } <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>;
<span class="hljs-keyword">import</span> { motion, AnimatePresence } <span class="hljs-keyword">from</span> <span class="hljs-string">"framer-motion"</span>;
</code></pre>
<p>We then create our carousel function which takes in the <code>images</code> prop  which will be an array of image URLs:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> Carousel = <span class="hljs-function">(<span class="hljs-params">{ images }</span>) =&gt;</span> {};
</code></pre>
<p>In our carousel function, we initialize a state variable with useState to keep track of the current image index we use <code>setCurrentIndex</code> as the corresponding function to update the index.</p>
<p>Next, we create 3 helper functions to handle user interactions which include:</p>
<ul>
<li>handleNext: this updates the currentIndex to the next index in order to change the image and if it reaches the end of the array it cycles back.</li>
<li>handlePrevious: this does the same as the handleNext function, but this time in reverse order. This allows us to go back to images.</li>
<li>handleDotClick: this takes an index as a parameter and updates the currentIndex. With this, we can jump forward and backward to images just by clicking the dots.</li>
</ul>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> Carousel = <span class="hljs-function">(<span class="hljs-params">{ images }</span>) =&gt;</span> {
  <span class="hljs-keyword">const</span> [currentIndex, setCurrentIndex] = useState(<span class="hljs-number">0</span>);

  <span class="hljs-keyword">const</span> handleNext = <span class="hljs-function">() =&gt;</span> {
    setCurrentIndex(<span class="hljs-function">(<span class="hljs-params">prevIndex</span>) =&gt;</span>
      prevIndex + <span class="hljs-number">1</span> === images.length ? <span class="hljs-number">0</span> : prevIndex + <span class="hljs-number">1</span>
    );
  };
  <span class="hljs-keyword">const</span> handlePrevious = <span class="hljs-function">() =&gt;</span> {
    setCurrentIndex(<span class="hljs-function">(<span class="hljs-params">prevIndex</span>) =&gt;</span>
      prevIndex - <span class="hljs-number">1</span> &lt; <span class="hljs-number">0</span> ? images.length - <span class="hljs-number">1</span> : prevIndex - <span class="hljs-number">1</span>
    );
  };
  <span class="hljs-keyword">const</span> handleDotClick = <span class="hljs-function">(<span class="hljs-params">index</span>) =&gt;</span> {
    setCurrentIndex(index);
  };
</code></pre>
<p>These are the helper functions we will need for our component</p>
<h3 id="heading-how-to-create-our-template">How to Create our Template</h3>
<p>Our template is a pretty simple one and is made up of our image, our slider direction, and the dots (indicator).</p>
<pre><code class="lang-jsx">  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"carousel"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">img</span>
          <span class="hljs-attr">key</span>=<span class="hljs-string">{currentIndex}</span>
          <span class="hljs-attr">src</span>=<span class="hljs-string">{images[currentIndex]}</span>
        /&gt;</span><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"slide_direction"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"left"</span> <span class="hljs-attr">onClick</span>=<span class="hljs-string">{handlePrevious}</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">svg</span>
            <span class="hljs-attr">xmlns</span>=<span class="hljs-string">"http://www.w3.org/2000/svg"</span>
            <span class="hljs-attr">height</span>=<span class="hljs-string">"20"</span>
            <span class="hljs-attr">viewBox</span>=<span class="hljs-string">"0 96 960 960"</span>
            <span class="hljs-attr">width</span>=<span class="hljs-string">"20"</span>
          &gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">path</span> <span class="hljs-attr">d</span>=<span class="hljs-string">"M400 976 0 576l400-400 56 57-343 343 343 343-56 57Z"</span> /&gt;</span>
          <span class="hljs-tag">&lt;/<span class="hljs-name">svg</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"right"</span> <span class="hljs-attr">onClick</span>=<span class="hljs-string">{handleNext}</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">svg</span>
            <span class="hljs-attr">xmlns</span>=<span class="hljs-string">"http://www.w3.org/2000/svg"</span>
            <span class="hljs-attr">height</span>=<span class="hljs-string">"20"</span>
            <span class="hljs-attr">viewBox</span>=<span class="hljs-string">"0 96 960 960"</span>
            <span class="hljs-attr">width</span>=<span class="hljs-string">"20"</span>
          &gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">path</span> <span class="hljs-attr">d</span>=<span class="hljs-string">"m304 974-56-57 343-343-343-343 56-57 400 400-400 400Z"</span> /&gt;</span>
          <span class="hljs-tag">&lt;/<span class="hljs-name">svg</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"indicator"</span>&gt;</span>
        {images.map((_, index) =&gt; (
          <span class="hljs-tag">&lt;<span class="hljs-name">div</span>
            <span class="hljs-attr">key</span>=<span class="hljs-string">{index}</span>
            <span class="hljs-attr">className</span>=<span class="hljs-string">{</span>`<span class="hljs-attr">dot</span> ${<span class="hljs-attr">currentIndex</span> === <span class="hljs-string">index</span> ? "<span class="hljs-attr">active</span>" <span class="hljs-attr">:</span> ""}`}
            <span class="hljs-attr">onClick</span>=<span class="hljs-string">{()</span> =&gt;</span> handleDotClick(index)}
          &gt;<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
        ))}
      <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  );
</code></pre>
<p>As you can see in the template, we display the image at the current index. Then we have a div of <code>slider_direction</code> which holds two divs with class names <code>left</code> and <code>right</code>. We created these as navigation buttons for the carousel. They use inline SVGs to display arrow icons, and their onClick handlers are set to <code>handlePrevious</code> and <code>handleNext</code>, respectively.</p>
<p>We also have an indicator div which we created to display a series of dots that represent each image in the carousel. It maps over the images array and creates a dot for each image, setting the active class for the dot corresponding to the <code>currentIndex</code>. </p>
<p>We then attached an onClick handler for each dot which is set to call <code>handleDotClick</code> with the index of the dot.</p>
<p>And that should be our template, for now. All that is left is to export the carousel component, import it into the <code>App.js</code> component, and add some CSS. Then we will be ready to start animating.</p>
<p>So we simply export our carousel function from our <code>Carousel.js</code> component.</p>
<pre><code class="lang-jsx"><span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> Carousel;
</code></pre>
<h2 id="heading-how-to-use-the-carousel-component">How to Use the Carousel Component</h2>
<p>We have created our carousel component. But to use it we have to import it into our App.js component:</p>
<pre><code class="lang-jsx"><span class="hljs-keyword">import</span> Carousel <span class="hljs-keyword">from</span> <span class="hljs-string">"./Carousel"</span>;
</code></pre>
<p>After that, we can create our images array, which will hold our image URLs.</p>
<pre><code class="lang-jsx"><span class="hljs-keyword">const</span> images = [
  <span class="hljs-string">"https://images.pexels.com/photos/169647/pexels-photo-169647.jpeg?auto=compress&amp;cs=tinysrgb&amp;w=600"</span>,
  <span class="hljs-string">"https://images.pexels.com/photos/313782/pexels-photo-313782.jpeg?auto=compress&amp;cs=tinysrgb&amp;w=1260&amp;h=750&amp;dpr=1"</span>,
  <span class="hljs-string">"https://images.pexels.com/photos/773471/pexels-photo-773471.jpeg?auto=compress&amp;cs=tinysrgb&amp;w=1260&amp;h=750&amp;dpr=1"</span>,
  <span class="hljs-string">"https://images.pexels.com/photos/672532/pexels-photo-672532.jpeg?auto=compress&amp;cs=tinysrgb&amp;w=1260&amp;h=750&amp;dpr=1"</span>,
  <span class="hljs-string">"https://images.pexels.com/photos/632522/pexels-photo-632522.jpeg?auto=compress&amp;cs=tinysrgb&amp;w=1260&amp;h=750&amp;dpr=1"</span>,
  <span class="hljs-string">"https://images.pexels.com/photos/777059/pexels-photo-777059.jpeg?auto=compress&amp;cs=tinysrgb&amp;w=1260&amp;h=750&amp;dpr=1"</span>,
];
</code></pre>
<p>These are just images I got from <a target="_blank" href="https://www.pexels.com/">pexels</a> – that's what we are gonna use for this project.</p>
<p>Next, we add our App function which will hold our application template.</p>
<pre><code class="lang-jsx"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">App</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"App"</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">header</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"App-header"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">h1</span>&gt;</span>Image Carousel using React and Framer Motion<span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">header</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">main</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">Carousel</span> <span class="hljs-attr">images</span>=<span class="hljs-string">{images}</span> /&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">main</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  );
}
<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> App;
</code></pre>
<p>As you can see, we have our header that just displays a header showing what our application is about. </p>
<p>Then we have the main section which has our carousel component added and takes in a prop of the images array. If you recall, this was the prop we used in our carousel component to display images.</p>
<p>Lastly, we export the App component so we can use it in the index.js file.</p>
<p>To see all this together with no styling, run the <code>npm run start</code> command. The application should look like this:</p>
<p><img src="https://i.imgur.com/xN2meFY.gif" alt="Image" width="600" height="411" loading="lazy"></p>
<p>Ugly right? Yes, I agree with you. But with just a few lines of CSS, this will be transformed. So let's dive in.</p>
<h3 id="heading-how-to-add-the-css">How to Add the CSS</h3>
<p>I don't want to create a separate style sheet for the carousel component, so we will do all our CSS in the App.css file. Don't forget to import your style sheet.</p>
<pre><code class="lang-jsx"><span class="hljs-keyword">import</span> <span class="hljs-string">"./App.css"</span>
</code></pre>
<p>This is our CSS:</p>
<pre><code class="lang-css"><span class="hljs-keyword">@import</span> url(<span class="hljs-string">"https://fonts.googleapis.com/css2?family=Oswald:wght@600&amp;display=swap"</span>);
<span class="hljs-selector-class">.App-header</span> {
  <span class="hljs-attribute">font-size</span>: <span class="hljs-number">1rem</span>;
  <span class="hljs-attribute">text-align</span>: center;
  <span class="hljs-attribute">font-family</span>: <span class="hljs-string">"Oswald"</span>, sans-serif;
  <span class="hljs-attribute">padding-bottom</span>: <span class="hljs-number">2rem</span>;
}
<span class="hljs-selector-class">.carousel-images</span> {
  <span class="hljs-attribute">position</span>: relative;
  <span class="hljs-attribute">border-radius</span>: <span class="hljs-number">10px</span>;
  <span class="hljs-attribute">height</span>: <span class="hljs-number">400px</span>;
  <span class="hljs-attribute">max-width</span>: <span class="hljs-number">650px</span>;
  <span class="hljs-attribute">margin</span>: auto;
  <span class="hljs-attribute">overflow</span>: hidden;
}
<span class="hljs-selector-class">.carousel-images</span> <span class="hljs-selector-tag">img</span> {
  <span class="hljs-attribute">width</span>: <span class="hljs-number">99%</span>;
  <span class="hljs-attribute">height</span>: <span class="hljs-number">99%</span>;
  <span class="hljs-attribute">border-radius</span>: <span class="hljs-number">8px</span>;
  <span class="hljs-attribute">border</span>: <span class="hljs-number">#ff00008e</span> solid <span class="hljs-number">2px</span>;
}
<span class="hljs-selector-class">.slide_direction</span> {
  <span class="hljs-attribute">display</span>: flex;
  <span class="hljs-attribute">justify-content</span>: space-between;
}
<span class="hljs-selector-class">.left</span>,
<span class="hljs-selector-class">.right</span> {
  <span class="hljs-attribute">background-color</span>: <span class="hljs-number">#fb666675</span>;
  <span class="hljs-attribute">color</span>: <span class="hljs-number">#fff</span>;
  <span class="hljs-attribute">padding</span>: <span class="hljs-number">10px</span> <span class="hljs-number">8px</span> <span class="hljs-number">8px</span> <span class="hljs-number">13px</span>;
  <span class="hljs-attribute">margin</span>: <span class="hljs-number">0</span> <span class="hljs-number">20px</span>;
  <span class="hljs-attribute">border-radius</span>: <span class="hljs-number">50%</span>;
  <span class="hljs-attribute">position</span>: absolute;
  <span class="hljs-attribute">top</span>: <span class="hljs-number">0</span>;
  <span class="hljs-attribute">bottom</span>: <span class="hljs-number">0</span>;
  <span class="hljs-attribute">margin</span>: auto <span class="hljs-number">10px</span>;
  <span class="hljs-attribute">height</span>: <span class="hljs-number">25px</span>;
  <span class="hljs-attribute">width</span>: <span class="hljs-number">25px</span>;
}
<span class="hljs-selector-class">.left</span> {
  <span class="hljs-attribute">left</span>: <span class="hljs-number">0</span>;
}
<span class="hljs-selector-class">.right</span> {
  <span class="hljs-attribute">right</span>: <span class="hljs-number">0</span>;
}
<span class="hljs-selector-class">.carousel-indicator</span> {
  <span class="hljs-attribute">margin-top</span>: <span class="hljs-number">20px</span>;
  <span class="hljs-attribute">display</span>: flex;
  <span class="hljs-attribute">justify-content</span>: center;
  <span class="hljs-attribute">gap</span>: <span class="hljs-number">20px</span>;
}
<span class="hljs-selector-class">.dot</span> {
  <span class="hljs-attribute">background-color</span>: <span class="hljs-number">#333</span>;
  <span class="hljs-attribute">width</span>: <span class="hljs-number">15px</span>;
  <span class="hljs-attribute">height</span>: <span class="hljs-number">15px</span>;
  <span class="hljs-attribute">border-radius</span>: <span class="hljs-number">50%</span>;
}
<span class="hljs-selector-class">.active</span> {
  <span class="hljs-attribute">background-color</span>: <span class="hljs-number">#fa2020</span>;
}
</code></pre>
<p>And here is the result with our CSS:  </p>
<p><img src="https://i.imgur.com/0CfxWn4.gif" alt="Image" width="600" height="425" loading="lazy"></p>
<p>You'll probably agree that this looks a whole lot better and is already fully functional.</p>
<p>Now let's move on to adding our animation using Framer Motion to give it a nice sliding look.</p>
<h2 id="heading-how-to-add-animation-to-the-carousel-component">How to Add Animation to the Carousel Component</h2>
<p>To start animating with Framer Motion there are a few concepts you must be familiar with because we will be using them often in this section. These concepts include:</p>
<ul>
<li>Variants: Think of a variant as a named group of properties. Its job is to define how an element should appear or animate. You can create different variants to represent different visual states or animations for an element, like <code>open</code>, <code>closed</code>, <code>hover</code>, and so on.</li>
<li>Initial: This is simply the state your object will posses before the animation kicks in.</li>
<li>Animate: This is simply the state your object will animate to, it's as simple as that.</li>
</ul>
<p>Back to the project, we'll add our animations to our carousel component. We have already imported the two properties which we will be needing – the <code>motion</code> and <code>AnimatePresence</code> properties. </p>
<p>I will be breaking this section into three parts because we will be adding animation to three parts of our code, including the image, the slider directions, and the indicator dot.</p>
<h3 id="heading-image-animation">Image Animation</h3>
<p>To animate the exit and entrance of an image, we need to wrap our <code>img</code> element with an <code>AnimationPresence</code>  component. This enables us to add animation whenever an image leaves or enters. Then we attach a <code>motion.</code> to our tag just like this.</p>
<pre><code class="lang-jsx"> &lt;AnimatePresence&gt;
  <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">motion.img</span> <span class="hljs-attr">key</span>=<span class="hljs-string">{currentIndex}</span> <span class="hljs-attr">src</span>=<span class="hljs-string">{images[currentIndex]}</span> /&gt;</span></span>
&lt;/AnimatePresence&gt;;
</code></pre>
<p>Next, we go outside our template and declare our variants.</p>
<pre><code class="lang-jsx">  <span class="hljs-keyword">const</span> slideVariants = {
    <span class="hljs-attr">hiddenRight</span>: {
      <span class="hljs-attr">x</span>: <span class="hljs-string">"100%"</span>,
      <span class="hljs-attr">opacity</span>: <span class="hljs-number">0</span>,
    },
    <span class="hljs-attr">hiddenLeft</span>: {
      <span class="hljs-attr">x</span>: <span class="hljs-string">"-100%"</span>,
      <span class="hljs-attr">opacity</span>: <span class="hljs-number">0</span>,
    },
    <span class="hljs-attr">visible</span>: {
      <span class="hljs-attr">x</span>: <span class="hljs-string">"0"</span>,
      <span class="hljs-attr">opacity</span>: <span class="hljs-number">1</span>,
      <span class="hljs-attr">transition</span>: {
        <span class="hljs-attr">duration</span>: <span class="hljs-number">1</span>,
      },
    },
    <span class="hljs-attr">exit</span>: {
      <span class="hljs-attr">opacity</span>: <span class="hljs-number">0</span>,
      <span class="hljs-attr">scale</span>: <span class="hljs-number">0.8</span>,
      <span class="hljs-attr">transition</span>: {
        <span class="hljs-attr">duration</span>: <span class="hljs-number">0.5</span>,
      },
    },
  };
</code></pre>
<p>As you can see, the <code>sliderVariants</code> has four properties:</p>
<ul>
<li>hiddenRight: this sets the opacity of the image to 0 and places it at the right side of the container.</li>
<li>hiddenLeft: this does the same as the hiddenRight but this time it's set on the left side.</li>
<li>visible: this is the property that will be called for the slide animation to happen from whichever position the image is to the center of the container.</li>
<li>exit: this animation controls the removal of the image from the screen as another image slides in.</li>
</ul>
<p>Now our variants are set. How do we tell where the image should slide in from? We need to set a direction state and update the state based on which of the <code>slide_direction</code>s was clicked.</p>
<pre><code class="lang-jsx">  <span class="hljs-keyword">const</span> [direction, setDirection] = useState(<span class="hljs-string">'left'</span>);
</code></pre>
<p>So we set the direction to start at the left. This is only logical since the first image to be displayed will be the first image. Then we go over to our helper function and set the direction depending on which direction was clicked.</p>
<pre><code class="lang-jsx">  <span class="hljs-keyword">const</span> handleNext = <span class="hljs-function">() =&gt;</span> {
    setDirection(<span class="hljs-string">"right"</span>);
    setCurrentIndex(<span class="hljs-function">(<span class="hljs-params">prevIndex</span>) =&gt;</span>
      prevIndex + <span class="hljs-number">1</span> === images.length ? <span class="hljs-number">0</span> : prevIndex + <span class="hljs-number">1</span>
    );
  };

  <span class="hljs-keyword">const</span> handlePrevious = <span class="hljs-function">() =&gt;</span> {
    setDirection(<span class="hljs-string">"left"</span>);

    setCurrentIndex(<span class="hljs-function">(<span class="hljs-params">prevIndex</span>) =&gt;</span>
      prevIndex - <span class="hljs-number">1</span> &lt; <span class="hljs-number">0</span> ? images.length - <span class="hljs-number">1</span> : prevIndex - <span class="hljs-number">1</span>
    );
  };

  <span class="hljs-keyword">const</span> handleDotClick = <span class="hljs-function">(<span class="hljs-params">index</span>) =&gt;</span> {
    setDirection(index &gt; currentIndex ? <span class="hljs-string">"right"</span> : <span class="hljs-string">"left"</span>);
    setCurrentIndex(index);
  };
</code></pre>
<p>You may have noticed that we didn't just set the state for the <code>handleNext</code> and <code>handlePrevious</code>. We also did for the <code>handleDotClick</code>. So whenever a previous or next dot is clicked the direction will be set accordingly.</p>
<p>Just a reminder – the purpose of direction is to set the initial state of the image so the slider can work as it ought to.</p>
<p>Now that our direction is set, let's use our variants in our <code>img</code> element.</p>
<pre><code class="lang-jsx">&lt;AnimatePresence&gt;
          <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">motion.img</span>
            <span class="hljs-attr">key</span>=<span class="hljs-string">{currentIndex}</span>
            <span class="hljs-attr">src</span>=<span class="hljs-string">{images[currentIndex]}</span>
            <span class="hljs-attr">variants</span>=<span class="hljs-string">{slideVariants}</span>
            <span class="hljs-attr">initial</span>=<span class="hljs-string">{direction</span> === <span class="hljs-string">"right"</span> ? "<span class="hljs-attr">hiddenRight</span>" <span class="hljs-attr">:</span> "<span class="hljs-attr">hiddenLeft</span>"}
            <span class="hljs-attr">animate</span>=<span class="hljs-string">"visible"</span>
            <span class="hljs-attr">exit</span>=<span class="hljs-string">"exit"</span>
          /&gt;</span></span>
        &lt;/AnimatePresence&gt;
</code></pre>
<p>So we add the <code>variants</code> prop and set it equal to the <code>slideVariants</code> we created. Then we added the initial prop and set it equal to a ternary operator. This sets the initial state of the image to either be <code>hiddenRight</code> or <code>hiddenLeft</code> depending on which of the <code>slider_direction</code> or <code>dot</code> was clicked. </p>
<p>Next, we add the animate property, which animates the image from the initial position to the position we set in the <code>visible</code> property. </p>
<p>Lastly, we add our exit property and set it to <code>exit</code>. This animates the image out of the screen when a new image enters.</p>
<p>There are lots of props you can use when working with Framer Motion. You can check the <a target="_blank" href="https://www.framer.com/motion/component/#props">documentation</a> to learn more about them.</p>
<p>And with that in place, our image carousel should be working perfectly.</p>
<p><img src="https://i.imgur.com/4VNWzsq.gif" alt="Image" width="600" height="425" loading="lazy"></p>
<h3 id="heading-sliders-and-dots-animation">Sliders and Dots Animation</h3>
<p>We could stop here, but I just want to add a few animations to my slide directions and dots.</p>
<pre><code class="lang-jsx">  <span class="hljs-keyword">const</span> slidersVariants = {
    <span class="hljs-attr">hover</span>: {
      <span class="hljs-attr">scale</span>: <span class="hljs-number">1.2</span>,
      <span class="hljs-attr">backgroundColor</span>: <span class="hljs-string">"#ff00008e"</span>,
    },
  }; 
<span class="hljs-keyword">const</span> dotsVariants = {
    <span class="hljs-attr">initial</span>: {
      <span class="hljs-attr">y</span>: <span class="hljs-number">0</span>,
    },
    <span class="hljs-attr">animate</span>: {
      <span class="hljs-attr">y</span>: <span class="hljs-number">-10</span>,
      <span class="hljs-attr">scale</span>: <span class="hljs-number">1.3</span>,
      <span class="hljs-attr">transition</span>: { <span class="hljs-attr">type</span>: <span class="hljs-string">"spring"</span>, <span class="hljs-attr">stiffness</span>: <span class="hljs-number">1000</span>, <span class="hljs-attr">damping</span>: <span class="hljs-string">"10"</span> },
    },
    <span class="hljs-attr">hover</span>: {
      <span class="hljs-attr">scale</span>: <span class="hljs-number">1.1</span>,
      <span class="hljs-attr">transition</span>: { <span class="hljs-attr">duration</span>: <span class="hljs-number">0.2</span> },
    },
  };
</code></pre>
<p>As usual, first we create our variants. For the <code>slidersVariants</code> we just add a hover property. For the <code>dotsVariants</code> we have three properties: initial, animate, and hover.</p>
<p>Just like we did with the <code>img</code> element, we will add <code>motion.</code> as a prefix to the element name in order to use Framer Motion.</p>
<pre><code class="lang-jsx">&lt;div className=<span class="hljs-string">"slide_direction"</span>&gt;
  <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">motion.div</span>
    <span class="hljs-attr">variants</span>=<span class="hljs-string">{slidersVariants}</span>
    <span class="hljs-attr">whileHover</span>=<span class="hljs-string">"hover"</span>
    <span class="hljs-attr">className</span>=<span class="hljs-string">"left"</span>
    <span class="hljs-attr">onClick</span>=<span class="hljs-string">{handlePrevious}</span>
  &gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">svg</span>
      <span class="hljs-attr">xmlns</span>=<span class="hljs-string">"http://www.w3.org/2000/svg"</span>
      <span class="hljs-attr">height</span>=<span class="hljs-string">"20"</span>
      <span class="hljs-attr">viewBox</span>=<span class="hljs-string">"0 96 960 960"</span>
      <span class="hljs-attr">width</span>=<span class="hljs-string">"20"</span>
    &gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">path</span> <span class="hljs-attr">d</span>=<span class="hljs-string">"M400 976 0 576l400-400 56 57-343 343 343 343-56 57Z"</span> /&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">svg</span>&gt;</span>
  <span class="hljs-tag">&lt;/<span class="hljs-name">motion.div</span>&gt;</span></span>
  <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">motion.div</span>
    <span class="hljs-attr">variants</span>=<span class="hljs-string">{slidersVariants}</span>
    <span class="hljs-attr">whileHover</span>=<span class="hljs-string">"hover"</span>
    <span class="hljs-attr">className</span>=<span class="hljs-string">"right"</span>
    <span class="hljs-attr">onClick</span>=<span class="hljs-string">{handleNext}</span>
  &gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">svg</span>
      <span class="hljs-attr">xmlns</span>=<span class="hljs-string">"http://www.w3.org/2000/svg"</span>
      <span class="hljs-attr">height</span>=<span class="hljs-string">"20"</span>
      <span class="hljs-attr">viewBox</span>=<span class="hljs-string">"0 96 960 960"</span>
      <span class="hljs-attr">width</span>=<span class="hljs-string">"20"</span>
    &gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">path</span> <span class="hljs-attr">d</span>=<span class="hljs-string">"m304 974-56-57 343-343-343-343 56-57 400 400-400 400Z"</span> /&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">svg</span>&gt;</span>
  <span class="hljs-tag">&lt;/<span class="hljs-name">motion.div</span>&gt;</span></span>
&lt;/div&gt;;
</code></pre>
<p>As you can see, we added our variants and set it equal to <code>slidersVariants</code>. Then we used a new property <code>whileHover</code> and set it equal to the over property we specified in our <code>slidersVariants</code> object.</p>
<pre><code class="lang-jsx">&lt;motion.div
  key={index}
  className={<span class="hljs-string">`dot <span class="hljs-subst">${currentIndex === index ? <span class="hljs-string">"active"</span> : <span class="hljs-string">""</span>}</span>`</span>}
  onClick={<span class="hljs-function">() =&gt;</span> handleDotClick(index)}
  initial=<span class="hljs-string">"initial"</span>
  animate={currentIndex === index ? <span class="hljs-string">"animate"</span> : <span class="hljs-string">""</span>}
  whileHover=<span class="hljs-string">"hover"</span>
  variants={dotsVariants}
&gt;&lt;/motion.div&gt;;
</code></pre>
<p>Here we didn't just add a whileHover prop. We also added an <code>initial</code> prop and an <code>animate</code> prop that animates the current image dot so it stands out. </p>
<p>In our <code>slidersVariants</code> object, we specified a transition type of spring which gives it the bouncy nature when the animation transition takes place.</p>
<p>Add all this together and our sleek Image Carousel is ready. Here is the final result:</p>
<p><img src="https://i.imgur.com/Bgghl7M.gif" alt="Image" width="600" height="425" loading="lazy"></p>
<p>Just for reference, this is the full code of the carousel component:</p>
<pre><code class="lang-jsx"><span class="hljs-keyword">import</span> { useState } <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>;
<span class="hljs-keyword">import</span> { motion, AnimatePresence } <span class="hljs-keyword">from</span> <span class="hljs-string">"framer-motion"</span>;

<span class="hljs-keyword">const</span> Carousel = <span class="hljs-function">(<span class="hljs-params">{ images }</span>) =&gt;</span> {
  <span class="hljs-keyword">const</span> [currentIndex, setCurrentIndex] = useState(<span class="hljs-number">0</span>);
  <span class="hljs-keyword">const</span> [direction, setDirection] = useState(<span class="hljs-literal">null</span>);

  <span class="hljs-keyword">const</span> slideVariants = {
    <span class="hljs-attr">hiddenRight</span>: {
      <span class="hljs-attr">x</span>: <span class="hljs-string">"100%"</span>,
      <span class="hljs-attr">opacity</span>: <span class="hljs-number">0</span>,
    },
    <span class="hljs-attr">hiddenLeft</span>: {
      <span class="hljs-attr">x</span>: <span class="hljs-string">"-100%"</span>,
      <span class="hljs-attr">opacity</span>: <span class="hljs-number">0</span>,
    },
    <span class="hljs-attr">visible</span>: {
      <span class="hljs-attr">x</span>: <span class="hljs-string">"0"</span>,
      <span class="hljs-attr">opacity</span>: <span class="hljs-number">1</span>,
      <span class="hljs-attr">transition</span>: {
        <span class="hljs-attr">duration</span>: <span class="hljs-number">1</span>,
      },
    },
    <span class="hljs-attr">exit</span>: {
      <span class="hljs-attr">opacity</span>: <span class="hljs-number">0</span>,
      <span class="hljs-attr">scale</span>: <span class="hljs-number">0.8</span>,
      <span class="hljs-attr">transition</span>: {
        <span class="hljs-attr">duration</span>: <span class="hljs-number">0.5</span>,
      },
    },
  };
  <span class="hljs-keyword">const</span> slidersVariants = {
    <span class="hljs-attr">hover</span>: {
      <span class="hljs-attr">scale</span>: <span class="hljs-number">1.2</span>,
      <span class="hljs-attr">backgroundColor</span>: <span class="hljs-string">"#ff00008e"</span>,
    },
  };
  <span class="hljs-keyword">const</span> dotsVariants = {
    <span class="hljs-attr">initial</span>: {
      <span class="hljs-attr">y</span>: <span class="hljs-number">0</span>,
    },
    <span class="hljs-attr">animate</span>: {
      <span class="hljs-attr">y</span>: <span class="hljs-number">-10</span>,
      <span class="hljs-attr">scale</span>: <span class="hljs-number">1.2</span>,
      <span class="hljs-attr">transition</span>: { <span class="hljs-attr">type</span>: <span class="hljs-string">"spring"</span>, <span class="hljs-attr">stiffness</span>: <span class="hljs-number">1000</span>, <span class="hljs-attr">damping</span>: <span class="hljs-string">"10"</span> },
    },
    <span class="hljs-attr">hover</span>: {
      <span class="hljs-attr">scale</span>: <span class="hljs-number">1.1</span>,
      <span class="hljs-attr">transition</span>: { <span class="hljs-attr">duration</span>: <span class="hljs-number">0.2</span> },
    },
  };

  <span class="hljs-keyword">const</span> handleNext = <span class="hljs-function">() =&gt;</span> {
    setDirection(<span class="hljs-string">"right"</span>);
    setCurrentIndex(<span class="hljs-function">(<span class="hljs-params">prevIndex</span>) =&gt;</span>
      prevIndex + <span class="hljs-number">1</span> === images.length ? <span class="hljs-number">0</span> : prevIndex + <span class="hljs-number">1</span>
    );
  };

  <span class="hljs-keyword">const</span> handlePrevious = <span class="hljs-function">() =&gt;</span> {
    setDirection(<span class="hljs-string">"left"</span>);

    setCurrentIndex(<span class="hljs-function">(<span class="hljs-params">prevIndex</span>) =&gt;</span>
      prevIndex - <span class="hljs-number">1</span> &lt; <span class="hljs-number">0</span> ? images.length - <span class="hljs-number">1</span> : prevIndex - <span class="hljs-number">1</span>
    );
  };

  <span class="hljs-keyword">const</span> handleDotClick = <span class="hljs-function">(<span class="hljs-params">index</span>) =&gt;</span> {
    setDirection(index &gt; currentIndex ? <span class="hljs-string">"right"</span> : <span class="hljs-string">"left"</span>);
    setCurrentIndex(index);
  };

  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"carousel"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"carousel-images"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">AnimatePresence</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">motion.img</span>
            <span class="hljs-attr">key</span>=<span class="hljs-string">{currentIndex}</span>
            <span class="hljs-attr">src</span>=<span class="hljs-string">{images[currentIndex]}</span>
            <span class="hljs-attr">initial</span>=<span class="hljs-string">{direction</span> === <span class="hljs-string">"right"</span> ? "<span class="hljs-attr">hiddenRight</span>" <span class="hljs-attr">:</span> "<span class="hljs-attr">hiddenLeft</span>"}
            <span class="hljs-attr">animate</span>=<span class="hljs-string">"visible"</span>
            <span class="hljs-attr">exit</span>=<span class="hljs-string">"exit"</span>
            <span class="hljs-attr">variants</span>=<span class="hljs-string">{slideVariants}</span>
          /&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">AnimatePresence</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"slide_direction"</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">motion.div</span>
            <span class="hljs-attr">variants</span>=<span class="hljs-string">{slidersVariants}</span>
            <span class="hljs-attr">whileHover</span>=<span class="hljs-string">"hover"</span>
            <span class="hljs-attr">className</span>=<span class="hljs-string">"left"</span>
            <span class="hljs-attr">onClick</span>=<span class="hljs-string">{handlePrevious}</span>
          &gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">svg</span>
              <span class="hljs-attr">xmlns</span>=<span class="hljs-string">"http://www.w3.org/2000/svg"</span>
              <span class="hljs-attr">height</span>=<span class="hljs-string">"20"</span>
              <span class="hljs-attr">viewBox</span>=<span class="hljs-string">"0 96 960 960"</span>
              <span class="hljs-attr">width</span>=<span class="hljs-string">"20"</span>
            &gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">path</span> <span class="hljs-attr">d</span>=<span class="hljs-string">"M400 976 0 576l400-400 56 57-343 343 343 343-56 57Z"</span> /&gt;</span>
            <span class="hljs-tag">&lt;/<span class="hljs-name">svg</span>&gt;</span>
          <span class="hljs-tag">&lt;/<span class="hljs-name">motion.div</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">motion.div</span>
            <span class="hljs-attr">variants</span>=<span class="hljs-string">{slidersVariants}</span>
            <span class="hljs-attr">whileHover</span>=<span class="hljs-string">"hover"</span>
            <span class="hljs-attr">className</span>=<span class="hljs-string">"right"</span>
            <span class="hljs-attr">onClick</span>=<span class="hljs-string">{handleNext}</span>
          &gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">svg</span>
              <span class="hljs-attr">xmlns</span>=<span class="hljs-string">"http://www.w3.org/2000/svg"</span>
              <span class="hljs-attr">height</span>=<span class="hljs-string">"20"</span>
              <span class="hljs-attr">viewBox</span>=<span class="hljs-string">"0 96 960 960"</span>
              <span class="hljs-attr">width</span>=<span class="hljs-string">"20"</span>
            &gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">path</span> <span class="hljs-attr">d</span>=<span class="hljs-string">"m304 974-56-57 343-343-343-343 56-57 400 400-400 400Z"</span> /&gt;</span>
            <span class="hljs-tag">&lt;/<span class="hljs-name">svg</span>&gt;</span>
          <span class="hljs-tag">&lt;/<span class="hljs-name">motion.div</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"carousel-indicator"</span>&gt;</span>
        {images.map((_, index) =&gt; (
          <span class="hljs-tag">&lt;<span class="hljs-name">motion.div</span>
            <span class="hljs-attr">key</span>=<span class="hljs-string">{index}</span>
            <span class="hljs-attr">className</span>=<span class="hljs-string">{</span>`<span class="hljs-attr">dot</span> ${<span class="hljs-attr">currentIndex</span> === <span class="hljs-string">index</span> ? "<span class="hljs-attr">active</span>" <span class="hljs-attr">:</span> ""}`}
            <span class="hljs-attr">onClick</span>=<span class="hljs-string">{()</span> =&gt;</span> handleDotClick(index)}
            initial="initial"
            animate={currentIndex === index ? "animate" : ""}
            whileHover="hover"
            variants={dotsVariants}
          &gt;<span class="hljs-tag">&lt;/<span class="hljs-name">motion.div</span>&gt;</span>
        ))}
      <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  );
};
<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> Carousel;
</code></pre>
<p>Check out the Git Repository on <a target="_blank" href="https://github.com/Cejay101/ImageCarousel">GitHub</a>.</p>
<p>Here is the site on <a target="_blank" href="https://image-carousel-cj.netlify.app/">Netlify</a>.</p>
<p><em>Just a note that there are accessibility issues with this code, and so it shouldn't be used in a production environment.</em></p>
<h2 id="heading-resources">Resources</h2>
<p>I understand that there might be some terms or syntax that might be unclear, especially if you are new to React or new to using Framer Motion. Here are some resources I would recommend if you want to learn more:</p>
<ul>
<li><a target="_blank" href="https://legacy.reactjs.org/docs">React Documentation</a></li>
<li><a target="_blank" href="https://www.framer.com/motion/">Framer Motion Documentation</a></li>
<li><a target="_blank" href="https://www.youtube.com/playlist?list=PL4cUxeGkcC9iHDnQfTHEVVceOEBsOf07i">Framer Motion Course</a></li>
</ul>
<h2 id="heading-conclusion">Conclusion</h2>
<p>In this article, we explored the process of designing an engaging and responsive image carousel using the powerful combination of React and Framer Motion, an animation and gesture library. </p>
<p>By incorporating components like <code>motion</code> and <code>AnimationPresence</code>, we wear able to walk through the steps to build a visually appealing carousel. This carousel showcases our images and delivers smooth transitions between images with captivating animations for an enhanced user experience.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Build an Interactive Accordion Component with React and GSAP ]]>
                </title>
                <description>
                    <![CDATA[ As websites become more sophisticated and user expectations continue to rise, web developers must search for ways to create more engaging and interactive user interfaces.  One powerful tool in a developer's arsenal is the accordion component, a versa... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/build-an-interactive-accordion-component-with-react-and-gsap/</link>
                <guid isPermaLink="false">66bb88fe7a6500a14ba5b765</guid>
                
                    <category>
                        <![CDATA[ animation ]]>
                    </category>
                
                    <category>
                        <![CDATA[ React ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Web Development ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ David Jaja ]]>
                </dc:creator>
                <pubDate>Tue, 25 Apr 2023 15:47:34 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2023/04/Cover-image-1.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>As websites become more sophisticated and user expectations continue to rise, web developers must search for ways to create more engaging and interactive user interfaces. </p>
<p>One powerful tool in a developer's arsenal is the accordion component, a versatile and widely-used element found on nearly every website. </p>
<p>In this article, we'll explore how to create a dynamic and visually-stunning accordion component using React and the GreenSock Animation Platform library (GSAP). </p>
<p>By combining the flexibility of React with the animation capabilities of GSAP, we'll craft a seamless and immersive user experience that will leave your visitors wanting more. So buckle up and get ready to advance your web development skills!</p>
<h2 id="heading-prerequisites">Prerequisites</h2>
<ul>
<li>Fundamentals of HTML and CSS</li>
<li>Fundamentals of ES6 JavaScript</li>
<li>Fundamentals of React and React Hooks.</li>
</ul>
<h2 id="heading-what-well-cover">What We'll Cover:</h2>
<ol>
<li><a class="post-section-overview" href="#heading-what-is-an-accordion-component">What is an accordion component?</a></li>
<li><a class="post-section-overview" href="#heading-the-importance-of-accordion-components-in-web-design">The importance of accordion components in web design</a></li>
<li><a class="post-section-overview" href="#heading-a-quick-overview-of-react-and-gsap">A quick overview of React and GSAP</a></li>
<li><a class="post-section-overview" href="#heading-how-to-set-up-your-development-environment">How to set up your development environment</a></li>
<li><a class="post-section-overview" href="#heading-breakdown-of-the-project">Breakdown of the project</a><br>– <a class="post-section-overview" href="#heading-the-user-interface-section">The user interface section</a><br>– <a class="post-section-overview" href="#heading-the-functionality-section">The functionality section</a><br>– <a class="post-section-overview" href="#heading-the-animation-section">The animation section</a></li>
<li><a class="post-section-overview" href="#heading-conclusion">Conclusion</a></li>
</ol>
<h2 id="heading-what-is-an-accordion-component">What is an Accordion Component?</h2>
<p>An accordion component is a UI element used to present a list of items in a compact manner. It consists of a vertical list of headers that expand and collapse their corresponding content when clicked. </p>
<p>This type of component is helpful because it allows users to quickly scan a list and expand only relevant items.</p>
<h2 id="heading-the-importance-of-accordion-components-in-web-design">The Importance of Accordion Components in Web Design</h2>
<p>Accordion components have become an essential part of modern web design, as they allow website developers to display large amounts of information in a compact and organized way.  </p>
<p>Accordion components are particularly useful for content-heavy websites where users may become overwhelmed by too much information on a single page. </p>
<p>They also serve uses such as:</p>
<ul>
<li>Navigation: Accordion components provide a simple and intuitive way for users to navigate through a website. By organizing content into collapsible sections, users can quickly find what they are looking for, without having to scroll through long pages.</li>
<li>Space-saving: Accordion components help save screen real estate by allowing website designers and developers to display multiple sections of content in a compact form factor. This is particularly important for mobile devices, where screen real estate is limited.</li>
<li>User experience: Accordion components can help improve the user experience by reducing clutter and making it easier for users to find the information they need. By keeping the user interface clean and organised, users are less likely to become overwhelmed or frustrated. Additionally, the interactive nature of accordion components can make the user experience more engaging and enjoyable.</li>
</ul>
<h2 id="heading-a-quick-overview-of-react-and-gsap">A Quick Overview of React and GSAP</h2>
<p>React is a JavaScript framework that streamlines the creation of dynamic user interfaces. It achieves this by enabling developers to create individual, reusable components that can be pieced together to form intricate and interactive interfaces. </p>
<p>This process involves breaking down the interface into smaller components that are more manageable and can be updated independently without affecting the entire UI.</p>
<p>GSAP, also known as GreenSock Animation Platform, is a JavaScript library designed to create high-quality animations and interactive experiences on the web. </p>
<p>This library offers a comprehensive set of tools to produce animations that are visually appealing and optimized for performance. With GSAP, developers can create animations with precision and have complete control over the animation's behaviour.</p>
<p>When used together, React and GSAP can create highly interactive and visually stunning user interfaces, such as accordion components. React provides the framework for creating the accordion component, while GSAP provides the tools for animating the component and making it interactive.</p>
<h2 id="heading-how-to-set-up-your-development-environment">How to Set Up Your Development Environment</h2>
<p>Before you can begin creating components in a React application, you need to set up your development environment. This includes installing <a target="_blank" href="https://nodejs.org/en/download">Node.js</a> and <a target="_blank" href="https://www.npmjs.com/package/download">npm</a> (Node Package Manager) on your computer.</p>
<h3 id="heading-how-to-create-a-react-project">How to Create a React Project</h3>
<p>After installing Node.js and npm, you can use the Create React App command-line tool to create a new React project. In your local terminal, run the command:</p>
<p>npx create-react-app react-gsap-dropdown</p>
<p>Then, open that folder with your code editor. This is what it should look like:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/04/001---Initial-view-after-cra.png" alt="Image" width="600" height="400" loading="lazy">
<em>Initial view after creating react app</em></p>
<p><strong>Note</strong>: I'll be using the <a target="_blank" href="https://code.visualstudio.com/download">VSCode Editor</a> for development in this tutorial, but any modern text editor should be sufficient.</p>
<p>Following that, remove all of the boilerplate styles and unnecessary files from your app.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/04/002---After-clearing-clutter-files.PNG" alt="Image" width="600" height="400" loading="lazy">
<em>After clearing clutter files and styles</em></p>
<p>The next step in the setup process is to install GSAP in your React app. Simply open the terminal in your code editor and run:</p>
<p>npm install gsap</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/04/installing-gsap.png" alt="Image" width="600" height="400" loading="lazy">
<em>Installing gsap</em></p>
<p>All that remains is to run <code>npm start</code>, which launches a development server in your browser and displays a blank page.</p>
<h2 id="heading-breakdown-of-the-project">Breakdown of the Project</h2>
<p>Before you begin building your project, it is important to understand that it is divided into three parts:</p>
<ul>
<li>The User Interface section</li>
<li>The Functionality section</li>
<li>The Animation section</li>
</ul>
<h3 id="heading-the-user-interface-section">The User Interface Section</h3>
<p>This section includes all of the mockups and styling needed to render your component on the page. Here’s a step-by-step of this section’s progress</p>
<p>First, create a parent element in your App component called <code>accordion__container</code><em>.</em> This element holds all the accordion items you wish to create.</p>
<p>Next, create three child items representing each accordion item which you would make expandable based on user interaction. So far your code structure should look something like this;</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"App"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"accordion__container"</span>&gt;</span>
       <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"accordion__item"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
       <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"accordion__item"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
       <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"accordion__item"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
</code></pre>
<p>In each accordion item, nest two child elements, the <code>accordion__header</code> and <code>accordion__details</code>. The <code>accordion__header</code> will hold the information displayed when the <code>accordion__item</code> is compact, and the <code>accordion__details</code> will hold the information when it’s expanded.</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"App"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"accordion__container"</span>&gt;</span>
       <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"accordion__item"</span>&gt;</span> 
          <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"accordion__header"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"accordion__details"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
       <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"accordion__item"</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"accordion__header"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"accordion__details"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
       <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
       <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"accordion__item"</span>&gt;</span> 
          <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"accordion__header"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"accordion__details"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
       <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
</code></pre>
<p>Adding content to both child elements gives you the following code:</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"accordion__container"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"accordion__item"</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"accordion__header"</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">p</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"accordion__number"</span>&gt;</span>01<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">p</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"accordion__name"</span>&gt;</span>The World's Tallest Building<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
          <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>

          <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"accordion__details"</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">ul</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">li</span>&gt;</span>
                The current tallest building in the world is the Burj Khalifa,
                located in Dubai, United Arab Emirates.
              <span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">li</span>&gt;</span>
                It stands at a height of 828 meters (2,716 feet) tall and has
                163 floors.
              <span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">li</span>&gt;</span>
                The building took six years to construct and was completed in
                2010.
              <span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
            <span class="hljs-tag">&lt;/<span class="hljs-name">ul</span>&gt;</span>
          <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>

        <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"accordion__item"</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"accordion__header"</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">p</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"accordion__number"</span>&gt;</span>02<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">p</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"accordion__name"</span>&gt;</span>
              Famous Inventors and Their Inventions
            <span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
          <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"accordion__details"</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">ul</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">li</span>&gt;</span>
                Nikola Tesla, a Serbian-American inventor, is credited with the
                invention of the AC (alternating current) electrical system.
              <span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">li</span>&gt;</span>
                Thomas Edison, an American inventor, is credited with the
                invention of the light bulb.
              <span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">li</span>&gt;</span>
                Alexander Graham Bell, a Scottish-born American inventor, is
                credited with the invention of the telephone.
              <span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
            <span class="hljs-tag">&lt;/<span class="hljs-name">ul</span>&gt;</span>
          <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"accordion__item"</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"accordion__header"</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">p</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"accordion__number"</span>&gt;</span>03<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">p</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"accordion__name"</span>&gt;</span>Largest Deserts in the World<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
          <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"accordion__details"</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">ul</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">li</span>&gt;</span>
                The Sahara Desert, located in Africa, is the largest hot desert
                in the world and covers an area of 9.2 million square kilometers
                (3.6 million square miles).
              <span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">li</span>&gt;</span>
                The Antarctic Desert, located in Antarctica, is the largest cold
                desert in the world and covers an area of 14 million square
                kilometers (5.4 million square miles).
              <span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">li</span>&gt;</span>
                The Arabian Desert, located in the Middle East, is the
                third-largest desert in the world and covers an area of 2.33
                million square kilometers (900,000 square miles).
              <span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
            <span class="hljs-tag">&lt;/<span class="hljs-name">ul</span>&gt;</span>
          <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
</code></pre>
<p>We added a <code>number</code> and <code>name</code> element to the <code>accordion__header</code> element, and an unordered list with list items to the <code>accordion__details</code> element.</p>
<p>Taking a look at the component in your browser, you should see this:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/04/004---Initial-component-render-with-no-styling.png" alt="Image" width="600" height="400" loading="lazy">
<em>Initial component render with no styling</em></p>
<p>At the moment, your component doesn’t look like much, so add the styling below.</p>
<pre><code class="lang-css">
<span class="hljs-keyword">@import</span> url(<span class="hljs-string">"https://fonts.googleapis.com/css2?family=Dongle:wght@300;400&amp;display=swap"</span>);

* {
  <span class="hljs-attribute">margin</span>: <span class="hljs-number">0</span>;
  <span class="hljs-attribute">padding</span>: <span class="hljs-number">0</span>;
  <span class="hljs-attribute">box-sizing</span>: border-box;
}
<span class="hljs-selector-tag">body</span> {
  <span class="hljs-attribute">font-family</span>: <span class="hljs-string">"Dongle"</span>, sans-serif;
}
<span class="hljs-selector-class">.App</span> {
  <span class="hljs-attribute">min-height</span>: <span class="hljs-number">100vh</span>;
  <span class="hljs-attribute">display</span>: flex;
  <span class="hljs-attribute">justify-content</span>: center;
}
<span class="hljs-selector-class">.accordion__container</span> {
  <span class="hljs-attribute">display</span>: flex;
  <span class="hljs-attribute">flex-direction</span>: column;
  <span class="hljs-attribute">gap</span>: <span class="hljs-number">1rem</span>;
  <span class="hljs-attribute">margin-top</span>: <span class="hljs-number">25px</span>;
}
<span class="hljs-selector-class">.accordion__item</span> {
  <span class="hljs-attribute">display</span>: flex;
  <span class="hljs-attribute">flex-direction</span>: column;
  <span class="hljs-attribute">width</span>: <span class="hljs-number">750px</span>;
  <span class="hljs-attribute">box-shadow</span>: <span class="hljs-number">0</span> <span class="hljs-number">0</span> <span class="hljs-number">32px</span> <span class="hljs-built_in">rgba</span>(<span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0.1</span>);
  <span class="hljs-attribute">border-top</span>: <span class="hljs-number">4px</span> solid transparent;
}
<span class="hljs-selector-class">.accordion__header</span> {
  <span class="hljs-attribute">display</span>: flex;
  <span class="hljs-attribute">gap</span>: <span class="hljs-number">2rem</span>;
  <span class="hljs-attribute">align-items</span>: center;
  <span class="hljs-attribute">cursor</span>: pointer;
  <span class="hljs-attribute">padding</span>: <span class="hljs-number">1rem</span> <span class="hljs-number">2rem</span>;
}
<span class="hljs-selector-class">.accordion__header</span><span class="hljs-selector-pseudo">:hover</span> {
  <span class="hljs-attribute">background</span>: <span class="hljs-number">#e7eaed</span>;
}
<span class="hljs-selector-class">.accordion__number</span> {
  <span class="hljs-attribute">font-size</span>: <span class="hljs-number">40px</span>;
  <span class="hljs-attribute">color</span>: <span class="hljs-number">#ced4da</span>;
}
<span class="hljs-selector-class">.accordion__name</span> {
  <span class="hljs-attribute">flex</span>: <span class="hljs-number">1</span>;
  <span class="hljs-attribute">font-size</span>: <span class="hljs-number">40px</span>;
}
<span class="hljs-selector-class">.accordion__details</span> {
  <span class="hljs-attribute">padding</span>: <span class="hljs-number">0</span> <span class="hljs-number">2rem</span>;
}
<span class="hljs-selector-class">.accordion__details</span> <span class="hljs-selector-tag">ul</span> {
  <span class="hljs-attribute">font-size</span>: <span class="hljs-number">30px</span>;
  <span class="hljs-attribute">padding</span>: <span class="hljs-number">1rem</span> <span class="hljs-number">2rem</span>;
  <span class="hljs-attribute">list-style-type</span>: circle;
}
</code></pre>
<p>This styling gives the <code>accordion__container</code> a fixed width and uses some Flexbox techniques together with basic CSS to give the component a nicer-looking appearance.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/04/005---Component-with-stylings-applied-1.png" alt="Image" width="600" height="400" loading="lazy">
<em>Rendered component with styling added</em></p>
<p>As you can see, your component is already well laid out and more appealing to users. But all the details of each accordion item are visible without any human interaction. </p>
<p>To solve this, you'll want to hide all the content in each <code>accordion__details</code> container by reducing its height and hiding any overflow.</p>
<pre><code class="lang-css"><span class="hljs-selector-class">.accordion__details</span> {
  <span class="hljs-attribute">overflow</span>: hidden;
  <span class="hljs-attribute">height</span>: <span class="hljs-number">0</span>;
}
</code></pre>
<p>This code produces this result:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/04/006--Component-after-hiding-details.PNG" alt="Image" width="600" height="400" loading="lazy">
<em>Component after hiding details</em></p>
<p>With this, you’ve concluded the interface section and can now move on to dynamically revealing the content of any accordion item you click on.</p>
<h3 id="heading-the-functionality-section">The Functionality Section</h3>
<p>In this section, we’re going to tackle the following:</p>
<ul>
<li>Dynamically display the details of each accordion based on a user’s click.</li>
<li>Ensure only one accordion tab is open at a time</li>
</ul>
<p>Starting off, create an <code>open</code> class which will contain styles that only the currently clicked accordion will have. This class will be added to any accordion item you click on.</p>
<pre><code class="lang-css"><span class="hljs-selector-class">.open</span> {
  <span class="hljs-attribute">border-color</span>: <span class="hljs-number">#087f5b</span>;
}

<span class="hljs-selector-class">.open</span> <span class="hljs-selector-class">.accordion__header</span>,
<span class="hljs-selector-class">.open</span> <span class="hljs-selector-class">.accordion__number</span> {
  <span class="hljs-attribute">color</span>: <span class="hljs-number">#087f5b</span>;
}

<span class="hljs-selector-class">.open</span> <span class="hljs-selector-class">.accordion__details</span> {
  <span class="hljs-attribute">height</span>: auto;
}
</code></pre>
<p>Then you'll create a variable with the <code>useState</code> hook. This hook is used to hold the current state of an accordion item (that is, if it’s open or not).</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> [openAccordion, setOpenAccordion] = useState(<span class="hljs-literal">null</span>);
</code></pre>
<p>After that, create a callback function that takes in a distinct index value from each <code>accordion__item</code> and compares it with the value in your state variable (<code>openAccordion</code>). The way the function works is, if the index value is distinct from the <code>openAccordion</code> value, the function sets the <code>openAccordion</code> value to the index value, else it sets the <code>openAccordion</code> to null.</p>
<pre><code class="lang-js"> <span class="hljs-keyword">const</span> handleAccordionClick = <span class="hljs-function">(<span class="hljs-params">index</span>) =&gt;</span> {
    <span class="hljs-keyword">if</span> (index !== openAccordion) {
        setOpenAccordion(index);
     } <span class="hljs-keyword">else</span> {
       setOpenAccordion(<span class="hljs-literal">null</span>);
    }
  };
</code></pre>
<p>This logic is used to conditionally render a class in your markup (that is, add or remove a class based on the item you click on). To make this function work, you use an <code>onClick</code> event on each <code>accordion__header</code>, and call each <code>handleAccordionClick</code> with a distinct <code>index</code> value.</p>
<pre><code class="lang-js">&lt;div className=<span class="hljs-string">"accordion__container"</span>&gt;
        <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"accordion__item"</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">div</span>
            <span class="hljs-attr">className</span>=<span class="hljs-string">"accordion__header"</span>
             // <span class="hljs-attr">HERE</span>
            <span class="hljs-attr">onClick</span>=<span class="hljs-string">{()</span> =&gt;</span> handleAccordionClick(0)}
          &gt;
            <span class="hljs-tag">&lt;<span class="hljs-name">p</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"accordion__number"</span>&gt;</span>01<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">p</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"accordion__name"</span>&gt;</span>The World's Tallest Building<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
          <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>

          <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"accordion__details"</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">ul</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">li</span>&gt;</span>
                The current tallest building in the world is the Burj Khalifa,
                located in Dubai, United Arab Emirates.
              <span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">li</span>&gt;</span>
                It stands at a height of 828 meters (2,716 feet) tall and has
                163 floors.
              <span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">li</span>&gt;</span>
                The building took six years to construct and was completed in
                2010.
              <span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
            <span class="hljs-tag">&lt;/<span class="hljs-name">ul</span>&gt;</span>
          <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>

        <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"accordion__item"</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">div</span>
            <span class="hljs-attr">className</span>=<span class="hljs-string">"accordion__header"</span>
             // <span class="hljs-attr">HERE</span>
            <span class="hljs-attr">onClick</span>=<span class="hljs-string">{()</span> =&gt;</span> handleAccordionClick(1)}
          &gt;
            <span class="hljs-tag">&lt;<span class="hljs-name">p</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"accordion__number"</span>&gt;</span>02<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">p</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"accordion__name"</span>&gt;</span>
              Famous Inventors and Their Inventions
            <span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
          <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"accordion__details"</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">ul</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">li</span>&gt;</span>
                Nikola Tesla, a Serbian-American inventor, is credited with the
                invention of the AC (alternating current) electrical system.
              <span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">li</span>&gt;</span>
                Thomas Edison, an American inventor, is credited with the
                invention of the light bulb.
              <span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">li</span>&gt;</span>
                Alexander Graham Bell, a Scottish-born American inventor, is
                credited with the invention of the telephone.
              <span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
            <span class="hljs-tag">&lt;/<span class="hljs-name">ul</span>&gt;</span>
          <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
        <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"accordion__item"</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">div</span>
            <span class="hljs-attr">className</span>=<span class="hljs-string">"accordion__header"</span>
            // <span class="hljs-attr">HERE</span>
            <span class="hljs-attr">onClick</span>=<span class="hljs-string">{()</span> =&gt;</span> handleAccordionClick(2)}
          &gt;
            <span class="hljs-tag">&lt;<span class="hljs-name">p</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"accordion__number"</span>&gt;</span>03<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">p</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"accordion__name"</span>&gt;</span>Largest Deserts in the World<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
          <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"accordion__details"</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">ul</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">li</span>&gt;</span>
                The Sahara Desert, located in Africa, is the largest hot desert
                in the world and covers an area of 9.2 million square kilometers
                (3.6 million square miles).
              <span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">li</span>&gt;</span>
                The Antarctic Desert, located in Antarctica, is the largest cold
                desert in the world and covers an area of 14 million square
                kilometers (5.4 million square miles).
              <span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">li</span>&gt;</span>
                The Arabian Desert, located in the Middle East, is the
                third-largest desert in the world and covers an area of 2.33
                million square kilometers (900,000 square miles).
              <span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
            <span class="hljs-tag">&lt;/<span class="hljs-name">ul</span>&gt;</span>
          <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
      &lt;/div&gt;
</code></pre>
<p>To confirm your logic, log both the <code>openAccordion</code> value and the <code>index</code> value to the console, and click on each accordion item.</p>
<pre><code class="lang-js">  <span class="hljs-keyword">const</span> handleAccordionClick = <span class="hljs-function">(<span class="hljs-params">index</span>) =&gt;</span> {
    <span class="hljs-built_in">console</span>.log(openAccordion, index);
    <span class="hljs-keyword">if</span> (index !== openAccordion) {
      setOpenAccordion(index);
    } <span class="hljs-keyword">else</span> {
      setOpenAccordion(<span class="hljs-literal">null</span>);
    }
  };
</code></pre>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/04/Testing-for-switching-logic.gif" alt="Image" width="600" height="400" loading="lazy">
<em>Testing the accordion logic</em></p>
<p>As you can see, clicking on the first item logs the current value of the <code>openAccordion</code> (null) and the current index (0) to the console. It also sets the value of <code>openAccordion</code> to the current index<em>.</em> </p>
<p>When you click on the next item, you notice that the <code>openAccordion</code> value was set to the previous index, implying that the value of the <code>openAccordion</code> was conditionally altered based on the user’s click.</p>
<p>Finally, clicking on the same element twice first sets the <code>openAccordion</code> to that element’s index, then to <code>null</code> since the else block of the function is fired when <code>openAccordion === index</code><em>.</em> </p>
<p>To show the content of each <code>accordion__item</code>, use a ternary operator to conditionally add the open class to each item.</p>
<pre><code class="lang-js">&lt;div className=<span class="hljs-string">"App"</span>&gt;

      <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"accordion__container"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">div</span>
        // <span class="hljs-attr">HERE</span>
          <span class="hljs-attr">className</span>=<span class="hljs-string">{</span>`<span class="hljs-attr">accordion__item</span>  ${<span class="hljs-attr">openAccordion</span> === <span class="hljs-string">0</span> ? "<span class="hljs-attr">open</span>" <span class="hljs-attr">:</span> ""}`}
        &gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">div</span>
            <span class="hljs-attr">className</span>=<span class="hljs-string">"accordion__header"</span>
            <span class="hljs-attr">onClick</span>=<span class="hljs-string">{()</span> =&gt;</span> handleAccordionClick(0)}
          &gt;
            <span class="hljs-tag">&lt;<span class="hljs-name">p</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"accordion__number"</span>&gt;</span>01<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">p</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"accordion__name"</span>&gt;</span>The World's Tallest Building<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
          <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>

          <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"accordion__details"</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">ul</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">li</span>&gt;</span>
                The current tallest building in the world is the Burj Khalifa,
                located in Dubai, United Arab Emirates.
              <span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">li</span>&gt;</span>
                It stands at a height of 828 meters (2,716 feet) tall and has
                163 floors.
              <span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">li</span>&gt;</span>
                The building took six years to construct and was completed in
                2010.
              <span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
            <span class="hljs-tag">&lt;/<span class="hljs-name">ul</span>&gt;</span>
          <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>

        <span class="hljs-tag">&lt;<span class="hljs-name">div</span>
        // <span class="hljs-attr">HERE</span>
          <span class="hljs-attr">className</span>=<span class="hljs-string">{</span>`<span class="hljs-attr">accordion__item</span>  ${<span class="hljs-attr">openAccordion</span> === <span class="hljs-string">1</span> ? "<span class="hljs-attr">open</span>" <span class="hljs-attr">:</span> ""}`}
        &gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">div</span>
            <span class="hljs-attr">className</span>=<span class="hljs-string">"accordion__header"</span>
            <span class="hljs-attr">onClick</span>=<span class="hljs-string">{()</span> =&gt;</span> handleAccordionClick(1)}
          &gt;
            <span class="hljs-tag">&lt;<span class="hljs-name">p</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"accordion__number"</span>&gt;</span>02<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">p</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"accordion__name"</span>&gt;</span>
              Famous Inventors and Their Inventions
            <span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
          <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"accordion__details"</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">ul</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">li</span>&gt;</span>
                Nikola Tesla, a Serbian-American inventor, is credited with the
                invention of the AC (alternating current) electrical system.
              <span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">li</span>&gt;</span>
                Thomas Edison, an American inventor, is credited with the
                invention of the light bulb.
              <span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">li</span>&gt;</span>
                Alexander Graham Bell, a Scottish-born American inventor, is
                credited with the invention of the telephone.
              <span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
            <span class="hljs-tag">&lt;/<span class="hljs-name">ul</span>&gt;</span>
          <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">div</span>
        // <span class="hljs-attr">HERE</span>
          <span class="hljs-attr">className</span>=<span class="hljs-string">{</span>`<span class="hljs-attr">accordion__item</span>  ${<span class="hljs-attr">openAccordion</span> === <span class="hljs-string">2</span> ? "<span class="hljs-attr">open</span>" <span class="hljs-attr">:</span> ""}`}
        &gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">div</span>
            <span class="hljs-attr">className</span>=<span class="hljs-string">"accordion__header"</span>
            <span class="hljs-attr">onClick</span>=<span class="hljs-string">{()</span> =&gt;</span> handleAccordionClick(2)}
          &gt;
            <span class="hljs-tag">&lt;<span class="hljs-name">p</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"accordion__number"</span>&gt;</span>03<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">p</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"accordion__name"</span>&gt;</span>Largest Deserts in the World<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
          <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"accordion__details"</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">ul</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">li</span>&gt;</span>
                The Sahara Desert, located in Africa, is the largest hot desert
                in the world and covers an area of 9.2 million square kilometers
                (3.6 million square miles).
              <span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">li</span>&gt;</span>
                The Antarctic Desert, located in Antarctica, is the largest cold
                desert in the world and covers an area of 14 million square
                kilometers (5.4 million square miles).
              <span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">li</span>&gt;</span>
                The Arabian Desert, located in the Middle East, is the
                third-largest desert in the world and covers an area of 2.33
                million square kilometers (900,000 square miles).
              <span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
            <span class="hljs-tag">&lt;/<span class="hljs-name">ul</span>&gt;</span>
          <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
    &lt;/div&gt;
</code></pre>
<p>The ternary operator checks if each <code>index</code> value matches the <code>openAccordion</code> value and adds the <code>open</code> class to the <code>accordion__item</code> if it does.</p>
<p>Testing your accordion component now gives the following result:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/04/Accordion-Working-without-animation-1.gif" alt="Image" width="600" height="400" loading="lazy">
<em>Working accordion without animation</em></p>
<p>As you can see, your accordion is already fully functional. Due to the logic you implemented with the ternary operator, only one accordion item can be opened at a time. Kudos!</p>
<p>Alas, your component is a little boring, right? It probably looks like every other accordion you’ve seen out there. So let’s spice up yours and make it the <em>talk of the tech community</em> by animating it 😉.</p>
<h3 id="heading-the-animation-section">The Animation Section</h3>
<p>At the moment when you toggle in the <code>open</code> class, the <code>accordion__details</code> element goes from showing no content to the full content in a split second without any animation whatsoever. It does this by alternating the value of the height from 0 to auto. </p>
<p>To make the accordion more interactive, you’ll use GSAP to animate the height of each accordion component when an accordion item is clicked.</p>
<p>Start by creating a reference of all the accordion items:</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> accordionRefs = useRef([]);
</code></pre>
<p><strong>Note</strong>: The <code>useRef</code> hook takes in an array because you’re selecting multiple elements. To distinctively target each element, use a <code>ref</code> attribute and pass in each individual index in the <code>ref</code>.</p>
<pre><code class="lang-js">&lt;div className=<span class="hljs-string">"App"</span>&gt;
      <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"accordion__container"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">div</span>
          <span class="hljs-attr">className</span>=<span class="hljs-string">{</span>`<span class="hljs-attr">accordion__item</span>  ${<span class="hljs-attr">openAccordion</span> === <span class="hljs-string">0</span> ? "<span class="hljs-attr">open</span>" <span class="hljs-attr">:</span> ""}`}
           // <span class="hljs-attr">HERE</span>
          <span class="hljs-attr">ref</span>=<span class="hljs-string">{(el)</span> =&gt;</span> (accordionRefs.current[0] = el)}
        &gt;
          <span class="hljs-tag">&lt;<span class="hljs-name">div</span>
            <span class="hljs-attr">className</span>=<span class="hljs-string">"accordion__header"</span>
            <span class="hljs-attr">onClick</span>=<span class="hljs-string">{()</span> =&gt;</span> handleAccordionClick(0)}
          &gt;
            <span class="hljs-tag">&lt;<span class="hljs-name">p</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"accordion__number"</span>&gt;</span>01<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">p</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"accordion__name"</span>&gt;</span>The World's Tallest Building<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
                     <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>

          <span class="hljs-tag">&lt;<span class="hljs-name">div</span>
            <span class="hljs-attr">className</span>=<span class="hljs-string">"accordion__details"</span>

          &gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">ul</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">li</span>&gt;</span>
                The current tallest building in the world is the Burj Khalifa,
                located in Dubai, United Arab Emirates.
              <span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">li</span>&gt;</span>
                It stands at a height of 828 meters (2,716 feet) tall and has
                163 floors.
              <span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">li</span>&gt;</span>
                The building took six years to construct and was completed in
                2010.
              <span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
            <span class="hljs-tag">&lt;/<span class="hljs-name">ul</span>&gt;</span>
          <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>

        <span class="hljs-tag">&lt;<span class="hljs-name">div</span>
          <span class="hljs-attr">className</span>=<span class="hljs-string">{</span>`<span class="hljs-attr">accordion__item</span> ${<span class="hljs-attr">openAccordion</span> === <span class="hljs-string">1</span> ? "<span class="hljs-attr">open</span>" <span class="hljs-attr">:</span> ""}`}
           // <span class="hljs-attr">HERE</span>
          <span class="hljs-attr">ref</span>=<span class="hljs-string">{(el)</span> =&gt;</span> (accordionRefs.current[1] = el)}
        &gt;
          <span class="hljs-tag">&lt;<span class="hljs-name">div</span>
            <span class="hljs-attr">className</span>=<span class="hljs-string">"accordion__header"</span>
            <span class="hljs-attr">onClick</span>=<span class="hljs-string">{()</span> =&gt;</span> handleAccordionClick(1)}
          &gt;
            <span class="hljs-tag">&lt;<span class="hljs-name">p</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"accordion__number"</span>&gt;</span>02<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">p</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"accordion__name"</span>&gt;</span>
              Famous Inventors and Their Inventions
            <span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
                      <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">div</span>
            <span class="hljs-attr">className</span>=<span class="hljs-string">"accordion__details"</span>

          &gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">ul</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">li</span>&gt;</span>
                Nikola Tesla, a Serbian-American inventor, is credited with the
                invention of the AC (alternating current) electrical system.
              <span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">li</span>&gt;</span>
                Thomas Edison, an American inventor, is credited with the
                invention of the light bulb.
              <span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">li</span>&gt;</span>
                Alexander Graham Bell, a Scottish-born American inventor, is
                credited with the invention of the telephone.
              <span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
            <span class="hljs-tag">&lt;/<span class="hljs-name">ul</span>&gt;</span>
          <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">div</span>
          <span class="hljs-attr">className</span>=<span class="hljs-string">{</span>`<span class="hljs-attr">accordion__item</span> ${<span class="hljs-attr">openAccordion</span> === <span class="hljs-string">2</span> ? "<span class="hljs-attr">open</span>" <span class="hljs-attr">:</span> ""}`}
          // <span class="hljs-attr">HERE</span>
          <span class="hljs-attr">ref</span>=<span class="hljs-string">{(el)</span> =&gt;</span> (accordionRefs.current[2] = el)}
        &gt;
          <span class="hljs-tag">&lt;<span class="hljs-name">div</span>
            <span class="hljs-attr">className</span>=<span class="hljs-string">"accordion__header"</span>
            <span class="hljs-attr">onClick</span>=<span class="hljs-string">{()</span> =&gt;</span> handleAccordionClick(2)}
          &gt;
            <span class="hljs-tag">&lt;<span class="hljs-name">p</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"accordion__number"</span>&gt;</span>03<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">p</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"accordion__name"</span>&gt;</span>Largest Deserts in the World<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
                      <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">div</span>
            <span class="hljs-attr">className</span>=<span class="hljs-string">"accordion__details"</span>

          &gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">ul</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">li</span>&gt;</span>
                The Sahara Desert, located in Africa, is the largest hot desert
                in the world and covers an area of 9.2 million square kilometers
                (3.6 million square miles).
              <span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">li</span>&gt;</span>
                The Antarctic Desert, located in Antarctica, is the largest cold
                desert in the world and covers an area of 14 million square
                kilometers (5.4 million square miles).
              <span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">li</span>&gt;</span>
                The Arabian Desert, located in the Middle East, is the
                third-largest desert in the world and covers an area of 2.33
                million square kilometers (900,000 square miles).
              <span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
            <span class="hljs-tag">&lt;/<span class="hljs-name">ul</span>&gt;</span>
          <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
    &lt;/div&gt;
</code></pre>
<p>Next, modify the <code>handleAccordionClick</code> function to add GSAP animations.</p>
<pre><code class="lang-js"><span class="hljs-keyword">if</span> (index === openAccordion) {
      gsap.to(
        accordionRefs.current[index].querySelector(<span class="hljs-string">".accordion__details"</span>),
        {
          <span class="hljs-attr">height</span>: <span class="hljs-number">0</span>,
          <span class="hljs-attr">duration</span>: <span class="hljs-number">1</span>,
          <span class="hljs-attr">ease</span>: <span class="hljs-string">"power1.inOut"</span>,
         }
      );
    }
</code></pre>
<p>Explaining the code snippet above:</p>
<ul>
<li>The conditional statement first checks if the index of the accordion item clicked matches the current state of the accordion.</li>
<li>Next, we use a GSAP method to add animations when the condition is true. The <code>gsap.to</code> method allows you to define the animation properties for an element and then smoothly transition the element from its current state to the specified end state over a period of time. The <code>gsap.to</code> method takes in 2 parameters, the target element and the specified behaviour of that target element.</li>
<li>We used a DOM traversing attribute (<code>.querySelector</code>) to select the element with the class name <code>accordion__details</code> inside that accordion item and attached some animation and styling to it.</li>
</ul>
<p><strong>Note:</strong> This code block will fire each time a particular accordion item is clicked twice, (when <code>index === openAccordion</code>), making this a closing animation.</p>
<p>Next you have to account for opening animations and closing previously open accordion items.</p>
<pre><code class="lang-js"><span class="hljs-keyword">else</span> {
      <span class="hljs-keyword">if</span> (openAccordion !== <span class="hljs-literal">null</span>) {
        gsap.to(
          accordionRefs.current[openAccordion].querySelector(
            <span class="hljs-string">".accordion__details"</span>
          ),
          {
            <span class="hljs-attr">height</span>: <span class="hljs-number">0</span>,
            <span class="hljs-attr">duration</span>: <span class="hljs-number">1</span>,
            <span class="hljs-attr">ease</span>: <span class="hljs-string">"power1.inOut"</span>,
          }
        );
      }
      setOpenAccordion(index);
      gsap.fromTo(
        accordionRefs.current[index].querySelector(<span class="hljs-string">".accordion__details"</span>),
        { <span class="hljs-attr">height</span>: <span class="hljs-number">0</span> },
        {
          <span class="hljs-attr">height</span>: <span class="hljs-string">"auto"</span>,
          <span class="hljs-attr">duration</span>: <span class="hljs-number">1</span>,
          <span class="hljs-attr">ease</span>: <span class="hljs-string">"power1.inOut"</span>,
        }
      );
    }
</code></pre>
<ul>
<li>The else block checks if the current value of the accordion is not null (if an accordion header has already been clicked) and uses GSAP to close the previously opened accordion by using the value stored in the <code>openAccordion</code> to target the appropriate element.</li>
<li>Then it updates the <code>openAccordion</code> value to the currently clicked element’s index. Finally, it uses a <code>gsap.fromTo</code> method to specify the animation of opening an accordion item. The <code>gsap.fromTo</code> takes in a starting and ending condition and animates the accordion item accordingly (from height: 0 to height: auto).</li>
</ul>
<p>Taking a look at the accordion now, you'll see the following result:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/04/Final-version-with-a-bug.gif" alt="Image" width="600" height="400" loading="lazy">
<em>Final version with a bug</em></p>
<p>And with that, you’ve successfully crafted an interactive accordion component, congrats! 🎉</p>
<p>There’s a small bug though. If you click on an accordion item after opening and closing it, it fails to open. This is because after the accordion item closes, the value of the <code>openAccordion</code> is still set to that accordion item’s index. This makes the code behave like there’s still an open accordion item even after closing it. </p>
<p>To solve this, attach an <code>onComplete</code> event to the <code>handleAccordionClick</code> function that sets the value of openAccordion to null after the animation completes. This way, each time you close the accordion, the value of <code>openAccordion</code> is reset and the accordion item can be reopened.</p>
<pre><code class="lang-js">  <span class="hljs-keyword">const</span> handleAccordionClick = <span class="hljs-function">(<span class="hljs-params">index</span>) =&gt;</span> {
    <span class="hljs-keyword">if</span> (index === openAccordion) {
      gsap.to(
        accordionRefs.current[index].querySelector(<span class="hljs-string">".accordion__details"</span>),
        {
          <span class="hljs-attr">height</span>: <span class="hljs-number">0</span>,
          <span class="hljs-attr">duration</span>: <span class="hljs-number">1</span>,
          <span class="hljs-attr">ease</span>: <span class="hljs-string">"power1.inOut"</span>,
          <span class="hljs-attr">onComplete</span>: <span class="hljs-function">() =&gt;</span> setOpenAccordion(<span class="hljs-literal">null</span>),
        }
      );
      <span class="hljs-built_in">console</span>.log(openAccordion);
    } <span class="hljs-keyword">else</span> {
      <span class="hljs-keyword">if</span> (openAccordion !== <span class="hljs-literal">null</span>) {
        gsap.to(
          accordionRefs.current[openAccordion].querySelector(
            <span class="hljs-string">".accordion__details"</span>
          ),
          {
            <span class="hljs-attr">height</span>: <span class="hljs-number">0</span>,
            <span class="hljs-attr">duration</span>: <span class="hljs-number">1</span>,
            <span class="hljs-attr">ease</span>: <span class="hljs-string">"power1.inOut"</span>,
          }
        );
      }
      setOpenAccordion(index);
      gsap.fromTo(
        accordionRefs.current[index].querySelector(<span class="hljs-string">".accordion__details"</span>),
        { <span class="hljs-attr">height</span>: <span class="hljs-number">0</span> },
        {
          <span class="hljs-attr">height</span>: <span class="hljs-string">"auto"</span>,
          <span class="hljs-attr">duration</span>: <span class="hljs-number">1</span>,
          <span class="hljs-attr">ease</span>: <span class="hljs-string">"power1.inOut"</span>,
        }
      );
    }
  };
</code></pre>
<p>And with that, let’s take a look at the final result:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/04/Final-bug-free-version-1.gif" alt="Image" width="600" height="400" loading="lazy">
<em>Final bug free version</em></p>
<p>For ease of accessibility, here’s the final full code:</p>
<pre><code class="lang-js"><span class="hljs-keyword">import</span> { useRef, useState } <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>;
<span class="hljs-keyword">import</span> <span class="hljs-string">"./App.css"</span>;
<span class="hljs-keyword">import</span> { gsap } <span class="hljs-keyword">from</span> <span class="hljs-string">"gsap"</span>;
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">App</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> [openAccordion, setOpenAccordion] = useState(<span class="hljs-literal">null</span>);
  <span class="hljs-keyword">const</span> accordionRefs = useRef([]);

  <span class="hljs-keyword">const</span> handleAccordionClick = <span class="hljs-function">(<span class="hljs-params">index</span>) =&gt;</span> {
    <span class="hljs-keyword">if</span> (index === openAccordion) {
      gsap.to(
        accordionRefs.current[index].querySelector(<span class="hljs-string">".accordion__details"</span>),
        {
          <span class="hljs-attr">height</span>: <span class="hljs-number">0</span>,
          <span class="hljs-attr">duration</span>: <span class="hljs-number">1</span>,
          <span class="hljs-attr">ease</span>: <span class="hljs-string">"power1.inOut"</span>,
          <span class="hljs-attr">onComplete</span>: <span class="hljs-function">() =&gt;</span> setOpenAccordion(<span class="hljs-literal">null</span>),
        }
      );
      <span class="hljs-comment">// console.log(openAccordion);</span>
    } <span class="hljs-keyword">else</span> {
      <span class="hljs-keyword">if</span> (openAccordion !== <span class="hljs-literal">null</span>) {
        gsap.to(
          accordionRefs.current[openAccordion].querySelector(
            <span class="hljs-string">".accordion__details"</span>
          ),
          {
            <span class="hljs-attr">height</span>: <span class="hljs-number">0</span>,
            <span class="hljs-attr">duration</span>: <span class="hljs-number">1</span>,
            <span class="hljs-attr">ease</span>: <span class="hljs-string">"power1.inOut"</span>,
          }
        );
      }
      setOpenAccordion(index);
      gsap.fromTo(
        accordionRefs.current[index].querySelector(<span class="hljs-string">".accordion__details"</span>),
        { <span class="hljs-attr">height</span>: <span class="hljs-number">0</span> },
        {
          <span class="hljs-attr">height</span>: <span class="hljs-string">"auto"</span>,
          <span class="hljs-attr">duration</span>: <span class="hljs-number">1</span>,
          <span class="hljs-attr">ease</span>: <span class="hljs-string">"power1.inOut"</span>,
        }
      );
    }
  };

  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"App"</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"accordion__container"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">div</span>
          <span class="hljs-attr">className</span>=<span class="hljs-string">{</span>`<span class="hljs-attr">accordion__item</span>  ${<span class="hljs-attr">openAccordion</span> === <span class="hljs-string">0</span> ? "<span class="hljs-attr">open</span>" <span class="hljs-attr">:</span> ""}`}
          <span class="hljs-attr">ref</span>=<span class="hljs-string">{(el)</span> =&gt;</span> (accordionRefs.current[0] = el)}
        &gt;
          <span class="hljs-tag">&lt;<span class="hljs-name">div</span>
            <span class="hljs-attr">className</span>=<span class="hljs-string">"accordion__header"</span>
            <span class="hljs-attr">onClick</span>=<span class="hljs-string">{()</span> =&gt;</span> handleAccordionClick(0)}
          &gt;
            <span class="hljs-tag">&lt;<span class="hljs-name">p</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"accordion__number"</span>&gt;</span>01<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">p</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"accordion__name"</span>&gt;</span>The World's Tallest Building<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
          <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>

          <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"accordion__details"</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">ul</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">li</span>&gt;</span>
                The current tallest building in the world is the Burj Khalifa,
                located in Dubai, United Arab Emirates.
              <span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">li</span>&gt;</span>
                It stands at a height of 828 meters (2,716 feet) tall and has
                163 floors.
              <span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">li</span>&gt;</span>
                The building took six years to construct and was completed in
                2010.
              <span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
            <span class="hljs-tag">&lt;/<span class="hljs-name">ul</span>&gt;</span>
          <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>

        <span class="hljs-tag">&lt;<span class="hljs-name">div</span>
          <span class="hljs-attr">className</span>=<span class="hljs-string">{</span>`<span class="hljs-attr">accordion__item</span> ${<span class="hljs-attr">openAccordion</span> === <span class="hljs-string">1</span> ? "<span class="hljs-attr">open</span>" <span class="hljs-attr">:</span> ""}`}
          <span class="hljs-attr">ref</span>=<span class="hljs-string">{(el)</span> =&gt;</span> (accordionRefs.current[1] = el)}
        &gt;
          <span class="hljs-tag">&lt;<span class="hljs-name">div</span>
            <span class="hljs-attr">className</span>=<span class="hljs-string">"accordion__header"</span>
            <span class="hljs-attr">onClick</span>=<span class="hljs-string">{()</span> =&gt;</span> handleAccordionClick(1)}
          &gt;
            <span class="hljs-tag">&lt;<span class="hljs-name">p</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"accordion__number"</span>&gt;</span>02<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">p</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"accordion__name"</span>&gt;</span>
              Famous Inventors and Their Inventions
            <span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
          <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"accordion__details"</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">ul</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">li</span>&gt;</span>
                Nikola Tesla, a Serbian-American inventor, is credited with the
                invention of the AC (alternating current) electrical system.
              <span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">li</span>&gt;</span>
                Thomas Edison, an American inventor, is credited with the
                invention of the light bulb.
              <span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">li</span>&gt;</span>
                Alexander Graham Bell, a Scottish-born American inventor, is
                credited with the invention of the telephone.
              <span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
            <span class="hljs-tag">&lt;/<span class="hljs-name">ul</span>&gt;</span>
          <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">div</span>
          <span class="hljs-attr">className</span>=<span class="hljs-string">{</span>`<span class="hljs-attr">accordion__item</span> ${<span class="hljs-attr">openAccordion</span> === <span class="hljs-string">2</span> ? "<span class="hljs-attr">open</span>" <span class="hljs-attr">:</span> ""}`}
          <span class="hljs-attr">ref</span>=<span class="hljs-string">{(el)</span> =&gt;</span> (accordionRefs.current[2] = el)}
        &gt;
          <span class="hljs-tag">&lt;<span class="hljs-name">div</span>
            <span class="hljs-attr">className</span>=<span class="hljs-string">"accordion__header"</span>
            <span class="hljs-attr">onClick</span>=<span class="hljs-string">{()</span> =&gt;</span> handleAccordionClick(2)}
          &gt;
            <span class="hljs-tag">&lt;<span class="hljs-name">p</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"accordion__number"</span>&gt;</span>03<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">p</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"accordion__name"</span>&gt;</span>Largest Deserts in the World<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
          <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"accordion__details"</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">ul</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">li</span>&gt;</span>
                The Sahara Desert, located in Africa, is the largest hot desert
                in the world and covers an area of 9.2 million square kilometers
                (3.6 million square miles).
              <span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">li</span>&gt;</span>
                The Antarctic Desert, located in Antarctica, is the largest cold
                desert in the world and covers an area of 14 million square
                kilometers (5.4 million square miles).
              <span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">li</span>&gt;</span>
                The Arabian Desert, located in the Middle East, is the
                third-largest desert in the world and covers an area of 2.33
                million square kilometers (900,000 square miles).
              <span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
            <span class="hljs-tag">&lt;/<span class="hljs-name">ul</span>&gt;</span>
          <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  );
}
<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> App;
</code></pre>
<p>Here’s a link to the repository: <a target="_blank" href="https://github.com/Daiveedjay/React-Gsap-Accordion">Github</a></p>
<p>And the live version: <a target="_blank" href="https://react-gsap-accordion.netlify.app">Live Demo</a></p>
<p>As a bonus, I prepared a JSON file in the repo containing all the information filled into the accordion component to better aid you in writing cleaner and reusable code.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/04/007-Json-file.png" alt="Image" width="600" height="400" loading="lazy">
<em>JSON file</em></p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>In this tutorial, you learned how to create an accordion component using React and GSAP that's not only functional but also looks super cool! </p>
<p>Now you can impress your friends and colleagues with your accordion-making skills, and who knows – maybe you'll start a new trend of accordion-themed websites :) Just remember to use your powers for good and not evil, and always accordion responsibly.</p>
<h3 id="heading-contact-information">Contact Information</h3>
<p>Want to connect or contact me? Feel free to hit me up on the following:</p>
<ul>
<li>Twitter: <a target="_blank" href="https://twitter.com/JajaDavid8">@jajadavid8</a></li>
<li>LinkedIn: <a target="_blank" href="https://www.linkedin.com/in/david-jaja-8084251b4/">David Jaja</a></li>
<li>Email: Jajadavidjid@gmail.com</li>
</ul>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Improve User Experience  in React Apps – Animate Routes using Framer Motion ]]>
                </title>
                <description>
                    <![CDATA[ In the modern digital landscape, user experience (UX) has become a central focus of web development. Providing a smooth, captivating, and aesthetically pleasing interface can really influence user satisfaction and retention.  Route animation is a fre... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/improve-user-experience-in-react-by-animating-routes-using-framer-motion/</link>
                <guid isPermaLink="false">66bb890dadd24ba4273250e2</guid>
                
                    <category>
                        <![CDATA[ animation ]]>
                    </category>
                
                    <category>
                        <![CDATA[ React ]]>
                    </category>
                
                    <category>
                        <![CDATA[ user experience ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ David Jaja ]]>
                </dc:creator>
                <pubDate>Tue, 04 Apr 2023 22:27:19 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2023/04/Article-Cover.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>In the modern digital landscape, user experience (UX) has become a central focus of web development. Providing a smooth, captivating, and aesthetically pleasing interface can really influence user satisfaction and retention. </p>
<p>Route animation is a frequently underestimated aspect of UX that can substantially improve a website's interactivity. </p>
<p>In this tutorial, I'll walk you through the steps of incorporating route animations in React applications using Framer Motion, a powerful and user-friendly animation library.</p>
<h2 id="heading-importance-of-animating-routes-in-web-applications">Importance of Animating Routes in Web Applications</h2>
<p>Animating routes can make transitions between different pages or sections of a website more visually appealing and interactive. Smooth route animations enhance the overall user experience by providing a sense of continuity and fluidity. They can also minimise perceived loading times and keep users engaged while new content is fetched or rendered.</p>
<p>If you’re like I am, and you're a sucker for aesthetic animations, you’d agree that websites that have silky animations and transitions, especially between their parts (routes), tend to leave a stronger impression and keep you browsing longer than less animated ones.</p>
<h2 id="heading-a-brief-introduction-to-react-and-framer-motion">A Brief Introduction to React and Framer Motion</h2>
<p>React has become a widely-used JavaScript library for crafting user interfaces, especially in the context of single-page applications (SPAs). As an SPA-focused solution, React loads a single HTML page and dynamically alters the content based on user navigation within the app, through route changes.</p>
<p>Framer Motion, an open-source animation library designed for React, delivers a straightforward and expressive API for generating intricate animations. </p>
<p>The library boasts an extensive array of animation capabilities, including spring physics, gesture handling, and server-side rendering support. This makes Framer Motion an ideal choice for implementing route animations in React applications.</p>
<h2 id="heading-how-to-set-up-your-development-environment">How to Set Up Your Development Environment</h2>
<p>Before you can begin animating routes in a React application, you need to set up your development environment. This includes installing <a target="_blank" href="https://nodejs.org/en/download">Node.js</a> and <a target="_blank" href="https://www.npmjs.com/package/download">npm</a> (Node Package Manager) on your computer.</p>
<h3 id="heading-how-to-create-a-react-project">How to Create a React Project</h3>
<p>Once you have Node.js and npm installed, you can create a new React project using the Create React App command-line tool. Run the following command in your terminal:</p>
<pre><code>npx create-react-app react-framer-animation
</code></pre><p>After that, open that folder with your code editor. It should look something like this:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/04/001-Setting-up-and-opening-your-react-app.png" alt="Image" width="600" height="400" loading="lazy">
<em>Setting up and opening your React App</em></p>
<p><strong>Note</strong>: in this tutorial, I'll be using the <a target="_blank" href="https://code.visualstudio.com/download">VSCode Editor</a> for development but any modern text editor should suffice.</p>
<p>Next, you rid yourself of all the boilerplate styles and unnecessary files in your app.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/04/002-Clearing-the-clutter-files.png" alt="Image" width="600" height="400" loading="lazy">
<em>Clearing the clutter files</em></p>
<p>Your next setup step is to install <em>framer motion</em> and <em>react-router</em> in your React app. Simply open your code editor’s terminal and run:</p>
<pre><code>npm install framer-motion react-router-dom
</code></pre><p><img src="https://www.freecodecamp.org/news/content/images/2023/04/003-Installing-he-necessary-dependencies.jpg" alt="Image" width="600" height="400" loading="lazy">
<em>Installing the necessary dependencies</em></p>
<p>All that’s left is to run <code>npm start</code> which starts up a development server on your browser that opens a blank page.</p>
<h2 id="heading-how-react-router-works">How React Router Works</h2>
<p>React Router is a widely-used library for managing navigation and routing in React applications. It allows developers to create dynamic routes and handle route changes seamlessly (that is, navigating between pages or components).</p>
<p>To help you gain a better understanding, let’s set up routes for our project.</p>
<p>First, import all the necessary functionalities into your <code>App</code> component</p>
<pre><code class="lang-js"><span class="hljs-keyword">import</span> { BrowserRouter, NavLink, Route, Routes } <span class="hljs-keyword">from</span> <span class="hljs-string">"react-router-dom"</span>;
</code></pre>
<p>Then create the rest of the components which you’ll navigate through. To prevent tedious back and forths between components, all components will be created in the <code>App.js</code> component.</p>
<pre><code class="lang-js"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Home</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span>
      <span class="hljs-attr">className</span>=<span class="hljs-string">"home component"</span>
    &gt;</span>
     <span class="hljs-tag">&lt;<span class="hljs-name">h1</span>&gt;</span>  Home Component <span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  );
}

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Header</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"header"</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">span</span>&gt;</span>Header Component<span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">ul</span>&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">ul</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  );
}

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">About</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span>
      <span class="hljs-attr">className</span>=<span class="hljs-string">"about component"</span>
    &gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">h1</span>&gt;</span> About Component <span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  );
}

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Contact</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span>
      <span class="hljs-attr">className</span>=<span class="hljs-string">"contact component"</span>
    &gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">h1</span>&gt;</span> Contact Component <span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  );
}
</code></pre>
<p>To render these components on the browser, you simply embed them in the <code>App</code> component.</p>
<pre><code class="lang-js">
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">App</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">classname</span>=<span class="hljs-string">”App”</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">Header</span> /&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">Home</span> /&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">About</span> /&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">Contact</span> /&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  );
}
</code></pre>
<p>At an initial glance, your app should look something like this in the browser:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/04/004-Initial-rendering-of-your-components-without-any-styling.png" alt="Image" width="600" height="400" loading="lazy">
<em>Initial rendering of your components without any styling</em></p>
<p>To make your app look better, add these stylings:</p>
<pre><code class="lang-css"><span class="hljs-keyword">@import</span> url(<span class="hljs-string">"https://fonts.googleapis.com/css2?family=Rajdhani:wght@600&amp;display=swap"</span>);

<span class="hljs-selector-tag">body</span> {
  <span class="hljs-attribute">font-family</span>: <span class="hljs-string">"Rajdhani"</span>, sans-serif;
  <span class="hljs-attribute">margin</span>: <span class="hljs-number">0</span>;
  <span class="hljs-attribute">padding</span>: <span class="hljs-number">0</span>;
  <span class="hljs-attribute">box-sizing</span>: border-box;
}
<span class="hljs-selector-class">.header</span> {
  <span class="hljs-attribute">padding</span>: <span class="hljs-number">20px</span>;
  <span class="hljs-attribute">box-shadow</span>: <span class="hljs-number">3px</span> <span class="hljs-number">3px</span> <span class="hljs-number">5px</span> <span class="hljs-built_in">rgba</span>(<span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0.2</span>);
  <span class="hljs-attribute">display</span>: flex;
  <span class="hljs-attribute">align-items</span>: center;
  <span class="hljs-attribute">justify-content</span>: space-between;
  <span class="hljs-attribute">margin-bottom</span>: <span class="hljs-number">10px</span>;
}
<span class="hljs-selector-class">.header</span> <span class="hljs-selector-tag">span</span> {
  <span class="hljs-attribute">font-size</span>: <span class="hljs-number">20px</span>;
}

<span class="hljs-selector-class">.header</span> <span class="hljs-selector-tag">ul</span> {
  <span class="hljs-attribute">display</span>: flex;
  <span class="hljs-attribute">gap</span>: <span class="hljs-number">20px</span>;
}

<span class="hljs-selector-class">.header</span> <span class="hljs-selector-tag">ul</span> <span class="hljs-selector-tag">a</span> {
  <span class="hljs-attribute">text-decoration</span>: none;
  <span class="hljs-attribute">border</span>: <span class="hljs-number">1.5px</span> solid <span class="hljs-number">#555</span>;
  <span class="hljs-attribute">padding</span>: <span class="hljs-number">5px</span> <span class="hljs-number">10px</span>;
  <span class="hljs-attribute">color</span>: <span class="hljs-number">#333</span>;
}

<span class="hljs-selector-class">.component</span> {
  <span class="hljs-attribute">font-size</span>: <span class="hljs-number">30px</span>;
  <span class="hljs-attribute">height</span>: <span class="hljs-number">87vh</span>;
  <span class="hljs-attribute">display</span>: flex;
  <span class="hljs-attribute">justify-content</span>: center;
  <span class="hljs-attribute">align-items</span>: center;
}

<span class="hljs-selector-class">.home</span> {
  <span class="hljs-attribute">background</span>: <span class="hljs-built_in">rgb</span>(<span class="hljs-number">214</span>, <span class="hljs-number">223</span>, <span class="hljs-number">135</span>);
}
<span class="hljs-selector-class">.about</span> {
  <span class="hljs-attribute">background</span>: <span class="hljs-built_in">rgb</span>(<span class="hljs-number">115</span>, <span class="hljs-number">139</span>, <span class="hljs-number">243</span>);
}

<span class="hljs-selector-class">.contact</span> {
  <span class="hljs-attribute">background</span>: palevioletred;
}
</code></pre>
<p>Here's what it'll look like now:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/04/After-applying-css.gif" alt="Image" width="600" height="400" loading="lazy">
<em>App after applying CSS</em></p>
<p>With your components styled, you can begin setting up the routes.</p>
<p>First, wrap the contents of your <code>App</code> component with the <code>BrowserRouter</code><em>,</em> then further wrap the contents with the <code>Routes</code> function. You do this to specify the components you can route (navigate) between.</p>
<pre><code class="lang-js"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">App</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"App"</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">BrowserRouter</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">Header</span> /&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">Routes</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">Home</span> /&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">About</span> /&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">Contact</span> /&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">Routes</span>&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">BrowserRouter</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  );
}
</code></pre>
<p>Keep in mind the <code>header</code> component is not placed inside the <code>Routes</code> component because it’s going to appear on the page irrespective of the route you navigate to.</p>
<p>Then, you assign a route path to each component.</p>
<pre><code class="lang-js"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">App</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"App"</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">BrowserRouter</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">Header</span> /&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">Routes</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">Route</span> <span class="hljs-attr">path</span>=<span class="hljs-string">"/"</span> <span class="hljs-attr">element</span>=<span class="hljs-string">{</span>&lt;<span class="hljs-attr">Home</span> /&gt;</span>} /&gt;
          <span class="hljs-tag">&lt;<span class="hljs-name">Route</span> <span class="hljs-attr">path</span>=<span class="hljs-string">"/about"</span> <span class="hljs-attr">element</span>=<span class="hljs-string">{</span>&lt;<span class="hljs-attr">About</span> /&gt;</span>} /&gt;
          <span class="hljs-tag">&lt;<span class="hljs-name">Route</span> <span class="hljs-attr">path</span>=<span class="hljs-string">"/contact"</span> <span class="hljs-attr">element</span>=<span class="hljs-string">{</span>&lt;<span class="hljs-attr">Contact</span> /&gt;</span>} /&gt;
        <span class="hljs-tag">&lt;/<span class="hljs-name">Routes</span>&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">BrowserRouter</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  );
}
</code></pre>
<p>At the moment, since you’re in the root route (/), only the home component is visible.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/04/005-Home-page-after-setting-up-the-routes-1.png" alt="Image" width="600" height="400" loading="lazy">
<em>Home page after setting up the routes</em></p>
<p>In order to navigate between pages, you use the <code>NavLink</code> element in your <code>header</code> ul and specify a different route per <code>NavLink</code><em>.</em> This would enable easy routing per <code>NavLink</code> you click on.</p>
<pre><code class="lang-js"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Header</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"header"</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">span</span>&gt;</span>Header Component<span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">ul</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">NavLink</span> <span class="hljs-attr">to</span>=<span class="hljs-string">"/"</span>&gt;</span>Home<span class="hljs-tag">&lt;/<span class="hljs-name">NavLink</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">NavLink</span> <span class="hljs-attr">to</span>=<span class="hljs-string">"/about"</span>&gt;</span>About<span class="hljs-tag">&lt;/<span class="hljs-name">NavLink</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">NavLink</span> <span class="hljs-attr">to</span>=<span class="hljs-string">"/contact"</span>&gt;</span>Contact<span class="hljs-tag">&lt;/<span class="hljs-name">NavLink</span>&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">ul</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  );
}
</code></pre>
<p>With that, you’ve successfully set up route buttons for your components!</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/04/After-setting-up-routing-buttons.gif" alt="Image" width="600" height="400" loading="lazy">
<em>After setting up routing buttons</em></p>
<h2 id="heading-how-to-set-up-your-routes-for-animation">How to Set Up Your Routes for Animation</h2>
<p>Now, to my favourite part of this article – animating the routes. To animate routes in React with framer motion, you first import 2 properties.</p>
<pre><code class="lang-js"><span class="hljs-keyword">import</span> { motion, AnimatePresence } <span class="hljs-keyword">from</span> <span class="hljs-string">"framer-motion"</span>;
</code></pre>
<p>The <code>motion</code> property turns whatever element you prefix it to into a <code>motion</code> element that can be animated with Framer, and the <code>AnimatePresence</code> component enables smooth animations when adding, removing, or changing components from a <em>React component tree</em> (visual representation or hierarchy of all the components used in a React application).</p>
<p>To animate the routes, you start by wrapping the content of the <code>BrowserRouter</code> with the <code>AnimatePresence</code> component.</p>
<pre><code class="lang-js"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">App</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"App"</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">BrowserRouter</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">AnimatePresence</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">Header</span> /&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">Routes</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">Route</span> <span class="hljs-attr">path</span>=<span class="hljs-string">"/"</span> <span class="hljs-attr">element</span>=<span class="hljs-string">{</span>&lt;<span class="hljs-attr">Home</span> /&gt;</span>} /&gt;
            <span class="hljs-tag">&lt;<span class="hljs-name">Route</span> <span class="hljs-attr">path</span>=<span class="hljs-string">"/about"</span> <span class="hljs-attr">element</span>=<span class="hljs-string">{</span>&lt;<span class="hljs-attr">About</span> /&gt;</span>} /&gt;
            <span class="hljs-tag">&lt;<span class="hljs-name">Route</span> <span class="hljs-attr">path</span>=<span class="hljs-string">"/contact"</span> <span class="hljs-attr">element</span>=<span class="hljs-string">{</span>&lt;<span class="hljs-attr">Contact</span> /&gt;</span>} /&gt;
          <span class="hljs-tag">&lt;/<span class="hljs-name">Routes</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">AnimatePresence</span>&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">BrowserRouter</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  );
}
</code></pre>
<p>On its own, the <code>AnimatePresence</code> component can’t tell when a component has mounted or unmounted so you’ll need to listen for that change. </p>
<p>To do this, you use the <code>useLocation</code> hook which listens for when there’s a change in the URL of your app (that is, when the route has changed). But you’re plighted with an error when you import and invoke the <code>useLocation</code> hook in your <code>App</code> component.</p>
<pre><code class="lang-js"><span class="hljs-keyword">import</span> { useLocation } <span class="hljs-keyword">from</span> <span class="hljs-string">"react-router-dom"</span>
</code></pre>
<pre><code class="lang-js"> <span class="hljs-keyword">const</span> location = useLocation();
</code></pre>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/04/006-Error-using-useLocation.png" alt="Image" width="600" height="400" loading="lazy">
<em>Error using useLocation</em></p>
<p>This error is caused because the useLocation hook can only be used within a Router component (a component that’s not a descendant of a Router component), which provides the routing context for the hook.</p>
<p>To solve this, you need to do a little refactoring. First, you create a <code>LocationProvider</code> component. This component is a wrapper component that returns the <code>AnimationPresence</code>.</p>
<pre><code class="lang-js"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">LocationProvider</span>(<span class="hljs-params"></span>) </span>{  <span class="hljs-keyword">return</span> <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">AnimatePresence</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">AnimatePresence</span>&gt;</span></span>; }
</code></pre>
<p>You then pass in the <code>children</code> prop to the <code>LocationProvider</code> which the <code>AnimatePresence</code> component uses to wrap any child element that would have a routing animation when mounted or unmounted.</p>
<pre><code class="lang-js"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">LocationProvider</span>(<span class="hljs-params">{ children }</span>) </span>{
  <span class="hljs-keyword">return</span> <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">AnimatePresence</span>&gt;</span>{children}<span class="hljs-tag">&lt;/<span class="hljs-name">AnimatePresence</span>&gt;</span></span>;
}
</code></pre>
<p>Then you create a <code>RoutesWithAnimation</code> component where you specify each route and the element to be mounted in that route. In this component, you can now use the <code>useLocation</code> hook to check for when there’s a route change.</p>
<pre><code class="lang-js"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">RoutesWithAnimation</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> location = useLocation();

  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">Routes</span> <span class="hljs-attr">location</span>=<span class="hljs-string">{location}</span> <span class="hljs-attr">key</span>=<span class="hljs-string">{location.key}</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">Route</span> <span class="hljs-attr">path</span>=<span class="hljs-string">"/"</span> <span class="hljs-attr">element</span>=<span class="hljs-string">{</span>&lt;<span class="hljs-attr">Home</span> /&gt;</span>} /&gt;
      <span class="hljs-tag">&lt;<span class="hljs-name">Route</span> <span class="hljs-attr">path</span>=<span class="hljs-string">"/about"</span> <span class="hljs-attr">element</span>=<span class="hljs-string">{</span>&lt;<span class="hljs-attr">About</span> /&gt;</span>} /&gt;
      <span class="hljs-tag">&lt;<span class="hljs-name">Route</span> <span class="hljs-attr">path</span>=<span class="hljs-string">"/contact"</span> <span class="hljs-attr">element</span>=<span class="hljs-string">{</span>&lt;<span class="hljs-attr">Contact</span> /&gt;</span>} /&gt;
    <span class="hljs-tag">&lt;/<span class="hljs-name">Routes</span>&gt;</span></span>
  );
}
</code></pre>
<p><strong>Note</strong>: A <code>key</code> prop was passed in the <code>Routes</code> component which React uses to render the correct component when the location changes.</p>
<p>Finally, you clear the <code>App</code> component of all the routing logic you defined earlier and replace it with the <code>RoutesWithAnimation</code> nested in the <code>LocationProvider</code><em>.</em></p>
<pre><code class="lang-js"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">App</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"App"</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">BrowserRouter</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">Header</span> /&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">LocationProvider</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">RoutesWithAnimation</span> /&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">LocationProvider</span>&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">BrowserRouter</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  );
}
</code></pre>
<p>To confirm that you’re keeping track of the route changes, log the <code>location</code> value to the console and toggle between routes.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/04/Confirming-that-react-is-tracking-that-route-changes.gif" alt="Image" width="600" height="400" loading="lazy"></p>
<p>As you can see, each time you change the route, the route path is logged to the console, along with a unique <code>key</code> property.</p>
<h2 id="heading-how-to-animate-routes-with-framer">How to Animate Routes with Framer</h2>
<p>To animate anything in Framer, you need to specify the following.</p>
<ul>
<li>Variants: Variants are a way to define and animate the properties of a component. A variant is an object that contains one or more named sets of properties, where each set represents a different animation state. To create a variant for your routes, you first define a variant object:</li>
</ul>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> routeVariants = {}
</code></pre>
<ul>
<li>Initial animation state: In your variant, you specify the initial state of the animation by creating an initial animation object. For this project, the animation you’re creating involves each component sliding in from the bottom (y-axis) of the page. To do this, you initially translate the entire component out of the viewport:</li>
</ul>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> routeVariants = {
    <span class="hljs-attr">initial</span>: {
        <span class="hljs-attr">y</span>: <span class="hljs-string">'100vh'</span>
    }
}
</code></pre>
<ul>
<li>Final animation state: Next, you specify the animation when the component is mounted by specifying a final animation state:</li>
</ul>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> routeVariants = {
    <span class="hljs-attr">initial</span>: {
        <span class="hljs-attr">y</span>: <span class="hljs-string">'100vh'</span>
    }
    <span class="hljs-attr">final</span>: {
        <span class="hljs-attr">y</span>: <span class="hljs-string">'0vh'</span>
    }
}
</code></pre>
<p>In order to apply these new animation properties to your components, you first make each component a <em>motion</em> element by prefixing the <code>motion</code> keyword to it.</p>
<pre><code class="lang-js"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Home</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">return</span> <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">motion.div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"home component"</span>&gt;</span>  <span class="hljs-tag">&lt;<span class="hljs-name">h1</span>&gt;</span> Home Component <span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">motion.div</span>&gt;</span></span>;
}

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">About</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">return</span> <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">motion.div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"about component"</span>&gt;</span> <span class="hljs-tag">&lt;<span class="hljs-name">h1</span>&gt;</span> About Component <span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">motion.div</span>&gt;</span></span>;
}

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Contact</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">return</span> <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">motion.div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"contact component"</span>&gt;</span> <span class="hljs-tag">&lt;<span class="hljs-name">h1</span>&gt;</span> Contact Component <span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">motion.div</span>&gt;</span></span>;
}
</code></pre>
<p>Then, you pass in the <code>variants</code> object and each of the variants states to each component you wish to animate. The <code>initial</code> state is the unmounted state of the component and the <code>animate</code> state is the mounted state of the component.</p>
<pre><code class="lang-js"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Home</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">motion.div</span>
      <span class="hljs-attr">variants</span>=<span class="hljs-string">{routeVariants}</span>
      <span class="hljs-attr">initial</span>=<span class="hljs-string">"initial"</span>
      <span class="hljs-attr">animate</span>=<span class="hljs-string">"final"</span>
      <span class="hljs-attr">className</span>=<span class="hljs-string">"home component"</span>
    &gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">h1</span>&gt;</span> Home Component <span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">motion.div</span>&gt;</span></span>
  );
}

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">About</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">motion.div</span>
      <span class="hljs-attr">variants</span>=<span class="hljs-string">{routeVariants}</span>
      <span class="hljs-attr">initial</span>=<span class="hljs-string">"initial"</span>
      <span class="hljs-attr">animate</span>=<span class="hljs-string">"final"</span>
      <span class="hljs-attr">className</span>=<span class="hljs-string">"about component"</span>
    &gt;</span>
     <span class="hljs-tag">&lt;<span class="hljs-name">h1</span>&gt;</span>  About Component <span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">motion.div</span>&gt;</span></span>
  );
}

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Contact</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">motion.div</span>
      <span class="hljs-attr">variants</span>=<span class="hljs-string">{routeVariants}</span>
      <span class="hljs-attr">initial</span>=<span class="hljs-string">"initial"</span>
      <span class="hljs-attr">animate</span>=<span class="hljs-string">"final"</span>
      <span class="hljs-attr">className</span>=<span class="hljs-string">"contact component"</span>
    &gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">h1</span>&gt;</span> Contact Component <span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">motion.div</span>&gt;</span></span>
  );
}
</code></pre>
<p>With this, your animation should already be working.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/04/Initail-Routing-achieved-with-bouncy-effect.gif" alt="Image" width="600" height="400" loading="lazy">
<em>Initial routing animation with extra bouncy effect achieved</em></p>
<p>And voilà! You’ve successfully animated the routes in your React app. Kudos! 🚀</p>
<p>One thing you’d notice is how bouncy our transition is. It slightly spills into the header component when entering the page. This is because the default animation type in Framer is spring which behaves as such. </p>
<p>To reduce the effect, you can simply specify a <code>mass</code> property on the final animation state.</p>
<pre><code class="lang-js">final: {
    <span class="hljs-attr">y</span>: <span class="hljs-string">"0vh"</span>,
    <span class="hljs-attr">transition</span>: {
      <span class="hljs-attr">type</span>: <span class="hljs-string">"spring"</span>,
      <span class="hljs-attr">mass</span>: <span class="hljs-number">0.4</span>,
    },
  },
</code></pre>
<p>This property specifies the mass of the animated component. An increase in value of the mass of the animated component results in a more bouncy effect and vice versa.</p>
<p><strong>Note</strong>: The mass value is usually kept between 0 and 1. (0 being no springiness and 1 being a lot of springiness). Setting your animated mass to 0.4 yields the following:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/04/Initail-Routing-achieved.gif" alt="Image" width="600" height="400" loading="lazy">
<em>Extra routing bouncy effect solved</em></p>
<h3 id="heading-children-animations">Children Animations</h3>
<p>We can take this even further by animating the route separately from the content of that route.</p>
<p>Start by creating a child variants object for the headings in each component.</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> childVariants = {
  <span class="hljs-attr">initial</span>: {
    <span class="hljs-attr">opacity</span>: <span class="hljs-number">0</span>,
    <span class="hljs-attr">y</span>: <span class="hljs-string">"50px"</span>,
  },
  <span class="hljs-attr">final</span>: {
    <span class="hljs-attr">opacity</span>: <span class="hljs-number">1</span>,
    <span class="hljs-attr">y</span>: <span class="hljs-string">"0px"</span>,
    <span class="hljs-attr">transition</span>: {
      <span class="hljs-attr">duration</span>: <span class="hljs-number">0.5</span>,
      <span class="hljs-attr">delay</span>: <span class="hljs-number">0.5</span>,
    },
  },
};
</code></pre>
<p>The <code>childVariant</code> animates the children elements by moving them up 50px and making them visible by increasing the opacity. Finally, the delay makes that animation fire slightly after the parent component animation fires.</p>
<p>To make this animation effective, you make each h1 a motion element. After that, you define your variants and animation states in all the child elements you want to animate. Each h1 element should look something like this:</p>
<pre><code class="lang-js"> &lt;motion.h1 variants={childVariants} initial=<span class="hljs-string">"initial"</span> animate=<span class="hljs-string">"final"</span>&gt;
        <span class="hljs-comment">// Whatever component name was in here.</span>
&lt;/motion.h1&gt;
</code></pre>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/04/Final-Routing-animation.gif" alt="Image" width="600" height="400" loading="lazy">
<em>Final result with both routing and children animation achieved</em></p>
<p>And with that, you’ve implemented a pretty sleek routing animation with Framer, congratulations! 🎉</p>
<p>For reference, here’s the full code:</p>
<pre><code class="lang-js"><span class="hljs-keyword">import</span> {
  BrowserRouter,
  NavLink,
  Route,
  Routes,
  useLocation,
} <span class="hljs-keyword">from</span> <span class="hljs-string">"react-router-dom"</span>;

<span class="hljs-keyword">import</span> { motion, AnimatePresence } <span class="hljs-keyword">from</span> <span class="hljs-string">"framer-motion"</span>;

<span class="hljs-keyword">const</span> routeVariants = {
  <span class="hljs-attr">initial</span>: {
    <span class="hljs-attr">y</span>: <span class="hljs-string">"100vh"</span>,
  },
  <span class="hljs-attr">final</span>: {
    <span class="hljs-attr">y</span>: <span class="hljs-string">"0vh"</span>,
    <span class="hljs-attr">transition</span>: {
      <span class="hljs-attr">type</span>: <span class="hljs-string">"spring"</span>,
      <span class="hljs-attr">mass</span>: <span class="hljs-number">0.4</span>,
    },
  },
};

<span class="hljs-keyword">const</span> childVariants = {
  <span class="hljs-attr">initial</span>: {
    <span class="hljs-attr">opacity</span>: <span class="hljs-number">0</span>,
    <span class="hljs-attr">y</span>: <span class="hljs-string">"50px"</span>,
  },
  <span class="hljs-attr">final</span>: {
    <span class="hljs-attr">opacity</span>: <span class="hljs-number">1</span>,
    <span class="hljs-attr">y</span>: <span class="hljs-string">"0px"</span>,
    <span class="hljs-attr">transition</span>: {
      <span class="hljs-attr">duration</span>: <span class="hljs-number">0.5</span>,
      <span class="hljs-attr">delay</span>: <span class="hljs-number">0.5</span>,
    },
  },
};

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">App</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"App"</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">BrowserRouter</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">Header</span> /&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">LocationProvider</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">RoutesWithAnimation</span> /&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">LocationProvider</span>&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">BrowserRouter</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  );
}

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">LocationProvider</span>(<span class="hljs-params">{ children }</span>) </span>{
  <span class="hljs-keyword">return</span> <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">AnimatePresence</span>&gt;</span>{children}<span class="hljs-tag">&lt;/<span class="hljs-name">AnimatePresence</span>&gt;</span></span>;
}

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">RoutesWithAnimation</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> location = useLocation();
  <span class="hljs-built_in">console</span>.log(location);

  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">Routes</span> <span class="hljs-attr">location</span>=<span class="hljs-string">{location}</span> <span class="hljs-attr">key</span>=<span class="hljs-string">{location.key}</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">Route</span> <span class="hljs-attr">path</span>=<span class="hljs-string">"/"</span> <span class="hljs-attr">element</span>=<span class="hljs-string">{</span>&lt;<span class="hljs-attr">Home</span> /&gt;</span>} /&gt;
      <span class="hljs-tag">&lt;<span class="hljs-name">Route</span> <span class="hljs-attr">path</span>=<span class="hljs-string">"/about"</span> <span class="hljs-attr">element</span>=<span class="hljs-string">{</span>&lt;<span class="hljs-attr">About</span> /&gt;</span>} /&gt;
      <span class="hljs-tag">&lt;<span class="hljs-name">Route</span> <span class="hljs-attr">path</span>=<span class="hljs-string">"/contact"</span> <span class="hljs-attr">element</span>=<span class="hljs-string">{</span>&lt;<span class="hljs-attr">Contact</span> /&gt;</span>} /&gt;
    <span class="hljs-tag">&lt;/<span class="hljs-name">Routes</span>&gt;</span></span>
  );
}

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Header</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"header"</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">span</span>&gt;</span>Header Component<span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">ul</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">NavLink</span> <span class="hljs-attr">to</span>=<span class="hljs-string">"/"</span>&gt;</span>Home<span class="hljs-tag">&lt;/<span class="hljs-name">NavLink</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">NavLink</span> <span class="hljs-attr">to</span>=<span class="hljs-string">"/about"</span>&gt;</span>About<span class="hljs-tag">&lt;/<span class="hljs-name">NavLink</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">NavLink</span> <span class="hljs-attr">to</span>=<span class="hljs-string">"/contact"</span>&gt;</span>Contact<span class="hljs-tag">&lt;/<span class="hljs-name">NavLink</span>&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">ul</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  );
}

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Home</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">motion.div</span>
      <span class="hljs-attr">variants</span>=<span class="hljs-string">{routeVariants}</span>
      <span class="hljs-attr">initial</span>=<span class="hljs-string">"initial"</span>
      <span class="hljs-attr">animate</span>=<span class="hljs-string">"final"</span>
      <span class="hljs-attr">className</span>=<span class="hljs-string">"home component"</span>
    &gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">motion.h1</span> <span class="hljs-attr">variants</span>=<span class="hljs-string">{childVariants}</span> <span class="hljs-attr">initial</span>=<span class="hljs-string">"initial"</span> <span class="hljs-attr">animate</span>=<span class="hljs-string">"final"</span>&gt;</span>
        Home Component
      <span class="hljs-tag">&lt;/<span class="hljs-name">motion.h1</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">motion.div</span>&gt;</span></span>
  );
}

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">About</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">motion.div</span>
      <span class="hljs-attr">variants</span>=<span class="hljs-string">{routeVariants}</span>
      <span class="hljs-attr">initial</span>=<span class="hljs-string">"initial"</span>
      <span class="hljs-attr">animate</span>=<span class="hljs-string">"final"</span>

      <span class="hljs-attr">className</span>=<span class="hljs-string">"about component"</span>
    &gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">motion.h1</span> <span class="hljs-attr">variants</span>=<span class="hljs-string">{childVariants}</span> <span class="hljs-attr">initial</span>=<span class="hljs-string">"initial"</span> <span class="hljs-attr">animate</span>=<span class="hljs-string">"final"</span>&gt;</span>
        About Component
      <span class="hljs-tag">&lt;/<span class="hljs-name">motion.h1</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">motion.div</span>&gt;</span></span>
  );
}

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Contact</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">motion.div</span>
      <span class="hljs-attr">variants</span>=<span class="hljs-string">{routeVariants}</span>
      <span class="hljs-attr">initial</span>=<span class="hljs-string">"initial"</span>
      <span class="hljs-attr">animate</span>=<span class="hljs-string">"final"</span>

      <span class="hljs-attr">className</span>=<span class="hljs-string">"contact component"</span>
    &gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">motion.h1</span> <span class="hljs-attr">variants</span>=<span class="hljs-string">{childVariants}</span> <span class="hljs-attr">initial</span>=<span class="hljs-string">"initial"</span> <span class="hljs-attr">animate</span>=<span class="hljs-string">"final"</span>&gt;</span>
        Contact Component
      <span class="hljs-tag">&lt;/<span class="hljs-name">motion.h1</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">motion.div</span>&gt;</span></span>
  );
}
<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> App;
</code></pre>
<p>Here’s a link to the repository: <a target="_blank" href="https://github.com/Daiveedjay/Framer-Articl">GitHub</a></p>
<p>And the live version: <a target="_blank" href="https://react-framer-article.netlify.app/">Netlify</a></p>
<h2 id="heading-final-thoughts">Final Thoughts</h2>
<p>I’ve got to say, I had lots of fun writing this article and building this animation, and I hope you did too. (I also refreshed one too many times because I liked the animation effect 😉). </p>
<p>I was really motivated to put this article out there because when I learnt Framer motion a few weeks ago, I struggled to find up-to-date resources to teach me how to use it, especially ones that implemented it with the latest version of both tools (react-router v6 and Framer motion 10). So I hope this article provides a reference to a much more recent approach to routing animations with Framer.</p>
<h3 id="heading-resources">Resources</h3>
<p>To learn more about framer motion and the react-router, here are a couple of resources I’d recommend</p>
<ul>
<li><a target="_blank" href="https://www.youtube.com/watch?v=2V1WK-3HQNk&amp;list=PL4cUxeGkcC9iHDnQfTHEVVceOEBsOf07i">Framer Motion (For React)</a></li>
<li><a target="_blank" href="https://www.framer.com/motion/">Framer motion Docs</a></li>
<li><a target="_blank" href="https://www.youtube.com/watch?v=OMQ2QARHPo0&amp;list=PL4cUxeGkcC9iVKmtNuCeIswnQ97in2GGf">React Router In-depth</a></li>
<li><a target="_blank" href="https://www.youtube.com/watch?v=k2Zk5cbiZhg">React Router V6</a></li>
</ul>
<h2 id="heading-conclusion">Conclusion</h2>
<p>In conclusion, animating routes in a React application using Framer Motion can enhance the user experience by creating smooth and seamless transitions between different pages. </p>
<p>By incorporating components like <code>AnimatePresence</code>, <code>motion</code>, and <code>variants</code>, you can customize your app's animations, making it more engaging and visually appealing. </p>
<p>Implementing animations can improve the overall flow and navigation of your app, creating a more enjoyable and responsive experience for your users.</p>
<h3 id="heading-contact-information">Contact Information</h3>
<p>Want to connect or contact me? Feel free to hit me up on the following:</p>
<ul>
<li>Twitter: <a target="_blank" href="https://twitter.com/JajaDavid8">@jajadavid8</a></li>
<li>LinkedIn: <a target="_blank" href="https://www.linkedin.com/in/david-jaja-8084251b4/">David Jaja</a></li>
<li>Email: Jajadavidjid@gmail.com</li>
</ul>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Add Scroll Animations to a Page with JavaScript's Intersection Observer API ]]>
                </title>
                <description>
                    <![CDATA[ By Mwendwa Bundi Emma Sometimes, when you visit a website, you'll notice that certain elements or a particular section gets revealed dynamically as you scroll.  It's like the contents of that particular section weren't available to view until you scr... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/scroll-animations-with-javascript-intersection-observer-api/</link>
                <guid isPermaLink="false">66d460424bc8f441cb6df815</guid>
                
                    <category>
                        <![CDATA[ animation ]]>
                    </category>
                
                    <category>
                        <![CDATA[ api ]]>
                    </category>
                
                    <category>
                        <![CDATA[ JavaScript ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ freeCodeCamp ]]>
                </dc:creator>
                <pubDate>Fri, 24 Mar 2023 17:42:18 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2023/03/observer-api.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>By Mwendwa Bundi Emma</p>
<p>Sometimes, when you visit a website, you'll notice that certain elements or a particular section gets revealed dynamically as you scroll. </p>
<p>It's like the contents of that particular section weren't available to view until you scrolled into the section – but now, because you're there, the website decides to reveal these contents.</p>
<p>Sometimes this might happen in a matter of milliseconds, and other times it might load lazily. All these phenomena are made possible by JavaScript's Intersection Observer API. </p>
<h2 id="heading-what-is-the-intersection-observer-api">What is the Intersection Observer API?</h2>
<p>The Intersection Observer API is a browser API which watches for changes that intersect with the viewport and then executes a callback function in the code.</p>
<p>It works by allowing you to define an observer function that runs when the target element intersects another element or the browser's default viewport.</p>
<blockquote>
<p>The intersection observer API lets code register a call back function that is executed whenever an element they wish to monitor enters or exits another element or the amount by which the two intersect changes by a requested amount. - <a target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/API/Intersection_Observer_API">MDN web docs</a>.</p>
</blockquote>
<h3 id="heading-pre-requisites">Pre-requisites:</h3>
<ul>
<li>Basic knowledge of HTML, CSS and JavaScript. You've probably built a simple project with them before.</li>
<li>An IDE, preferably VS Code.</li>
<li>A browser, like Chrome.</li>
</ul>
<p>In this article, you'll learn how to build a simple web page with HTML, CSS and JavaScript. Then you'll use the Intersection Observer API to implement a simple scroll animation.</p>
<h2 id="heading-how-the-intersection-observer-api-works">How the Intersection Observer API Works</h2>
<p>So you might be wondering, what happens when you define an observer call-back function? What happens is that you pass in an <code>entries</code> parameter as an argument which then executes intersection command once the user scrolls to the target element.</p>
<p>For example:</p>
<pre><code class="lang-js">Const observer = <span class="hljs-keyword">new</span> IntersectionObserver(<span class="hljs-function"><span class="hljs-params">entries</span> =&gt;</span> {
    <span class="hljs-comment">// your set of conditions goes here</span>
})
</code></pre>
<p>Once you have defined your observer function, you are thus able to set out the conditions you wish to be met once the intersection happens.</p>
<p>To make such changes, there are different options that the API allows you to pass into your call-back function. These options are the second parameters you can pass in as arguments. They are:</p>
<h3 id="heading-threshold">Threshold</h3>
<p>The threshold option ranges from 0-1, and you can specify the threshold to mean the required percentage of the target element that should be on sight for <code>isIntersecting</code> to be <code>true</code>. Remember that the default is 0, so that when the target element is just slightly visible your call-back function implements as needed.</p>
<h3 id="heading-root-margin">Root Margin</h3>
<p>The root margin is quite important in that you can add it to the container viewport and thus define each side of the viewport. It also allows you to define your own nested area for the API. The same way you define margins in custom CSS is just how you do it for root margin in Intersection Observer API.</p>
<h3 id="heading-root">Root</h3>
<p>When defining the root, keep in mind that it must be an ancestor of the target element. Depending on what you're working on you might or might not have to define the root, as it always defaults to the browser's viewport when not defined.</p>
<p>Now that you are acquainted with the basics of how the Intersection Observer API works, it's time to see it in action.</p>
<h2 id="heading-how-to-build-a-page-with-html-and-css">How to Build a Page with HTML and CSS</h2>
<p>Here, you'll build a basic static page with HTML and CSS. This page works just fine as it is, but there are no scroll animations at the moment.</p>
<p>We'll use this page to demonstrate the changes that happen once we add the Intersection Observer API JS part.</p>
<p>You are also going to add an <code>animation</code> class which will be called in JS using the DOM.</p>
<p>Don't forget to link your style file to your JS file as well.</p>
<h3 id="heading-html">HTML</h3>
<pre><code class="lang-html"><span class="hljs-meta">&lt;!DOCTYPE <span class="hljs-meta-keyword">html</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">html</span> <span class="hljs-attr">lang</span>=<span class="hljs-string">"en"</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">head</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">charset</span>=<span class="hljs-string">"UTF-8"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">http-equiv</span>=<span class="hljs-string">"X-UA-Compatible"</span> <span class="hljs-attr">content</span>=<span class="hljs-string">"IE=edge"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"viewport"</span> <span class="hljs-attr">content</span>=<span class="hljs-string">"width=device-width, initial-scale=1.0"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">link</span> <span class="hljs-attr">rel</span>=<span class="hljs-string">"stylesheet"</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"style.css"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">script</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"app.js"</span> <span class="hljs-attr">defer</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">title</span>&gt;</span>Intersection observer<span class="hljs-tag">&lt;/<span class="hljs-name">title</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">head</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">body</span>&gt;</span>

    <span class="hljs-tag">&lt;<span class="hljs-name">section</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">h1</span>&gt;</span>
            Here we go!
        <span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>

    <span class="hljs-tag">&lt;/<span class="hljs-name">section</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">section</span>&gt;</span> 
        <span class="hljs-tag">&lt;<span class="hljs-name">h2</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"animation"</span>&gt;</span>What I do<span class="hljs-tag">&lt;/<span class="hljs-name">h2</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">p</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"animation"</span>&gt;</span>Welcome to my page, My name is Mwendwa Bundi. I am a front-end developer and technical writer. Tell me about you!
        <span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>

        <span class="hljs-tag">&lt;/<span class="hljs-name">section</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">section</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">h1</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"animation"</span>&gt;</span>
            Here we go. Again!
        <span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>

    <span class="hljs-tag">&lt;/<span class="hljs-name">section</span>&gt;</span>

<span class="hljs-tag">&lt;/<span class="hljs-name">body</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">html</span>&gt;</span>
</code></pre>
<h3 id="heading-css">CSS</h3>
<p>Now we'll add some styling to the page and also a center section defined in the HTML. This will help in showing the scroll animations as they ease in.</p>
<pre><code class="lang-css">* {
    <span class="hljs-attribute">margin</span>: <span class="hljs-number">0</span>;
    <span class="hljs-attribute">padding</span>: <span class="hljs-number">0</span>;
    <span class="hljs-attribute">box-sizing</span>: border-box;

}

<span class="hljs-selector-tag">body</span> {
    <span class="hljs-attribute">background-color</span>: aqua;
    <span class="hljs-attribute">color</span>: white;
}

<span class="hljs-selector-tag">section</span> {
    <span class="hljs-attribute">display</span>: flex;
    <span class="hljs-attribute">flex-direction</span>: column;
    <span class="hljs-attribute">justify-content</span>: center;
    <span class="hljs-attribute">align-items</span>: center;
    <span class="hljs-attribute">height</span>: <span class="hljs-number">100vh</span>;
}
</code></pre>
<p>This is how the page looks as of now:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/03/Animation.gif" alt="Image" width="600" height="400" loading="lazy">
<em>Basic webpage with HTML &amp; CSS</em></p>
<h2 id="heading-how-to-update-the-css">How to Update the CSS</h2>
<p>Before adding the JavaScript, you have to update your custom CSS with the required animation you wish to see. As it is right now, our basic page is static. Here's the code to add to your CSS:</p>
<pre><code class="lang-css">
<span class="hljs-selector-class">.animation</span> {
    <span class="hljs-attribute">opacity</span>: <span class="hljs-number">0</span>;
    <span class="hljs-attribute">transform</span>: <span class="hljs-built_in">translateX</span>(-<span class="hljs-number">300px</span>);
    <span class="hljs-attribute">transition</span>: all <span class="hljs-number">0.7s</span> ease-out;
    <span class="hljs-attribute">transition-delay</span>: <span class="hljs-number">0.4s</span>;

}

<span class="hljs-selector-class">.scroll-animation</span> {
    <span class="hljs-attribute">opacity</span>: <span class="hljs-number">1</span>;
    <span class="hljs-attribute">transform</span>: <span class="hljs-built_in">translateX</span>(<span class="hljs-number">0</span>);
}
</code></pre>
<p>The opacity before the scroll is set to <code>0</code> so that once the user scrolls into the target element, the items can appear. This is why the opacity changes to <code>1</code> as shown above.</p>
<h2 id="heading-how-to-add-the-javascript-functionality">How to Add the JavaScript Functionality</h2>
<p>The idea is that once the <code>p</code> tag with the class <code>animation</code> is in view, the call-back function will successfully run.</p>
<p>Go ahead and use the DOM to select the animation class from the HTML page.</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> the_animation = <span class="hljs-built_in">document</span>.querySelectorAll(<span class="hljs-string">'.animation'</span>)
</code></pre>
<p>Now, it's time to create an observer function:</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> observer = <span class="hljs-keyword">new</span> IntersectionObserver(<span class="hljs-function">(<span class="hljs-params">entries</span>) =&gt;</span> {
    entries.forEach(<span class="hljs-function">(<span class="hljs-params">entry</span>) =&gt;</span> {
        <span class="hljs-keyword">if</span> (entry.isIntersecting) {
            entry.target.classList.add(<span class="hljs-string">'scroll-animations'</span>)
        }
            <span class="hljs-keyword">else</span> {
                entry.target.classList.remove(<span class="hljs-string">'scroll-animation'</span>)
            }

    })
},
</code></pre>
<p>Here, you have used the <code>if/else</code> conditional statements to specify what should happen if <code>isIntersecting</code> is <code>true</code> and afterward.</p>
<p>For each entry, if the entry parameter is intersecting, you use the DOM to select the animations property that you defined in your custom CSS – else, it's removed. This means that no matter how many times the user scrolls back and forth, the animation will still occur. In other words, the call-back function will still run.</p>
<p>To make sure that the callback function does not run immediately when the target element is in view, define a threshold of <code>0.5</code> inside the function.</p>
<pre><code class="lang-js">{ <span class="hljs-attr">threshold</span>: <span class="hljs-number">0.5</span>
   });
</code></pre>
<p>To get your observer in motion, define a for loop. This for loop will iterate through all the classes termed animation and observe the conditions in your intersection observer API.</p>
<pre><code class="lang-js">
  <span class="hljs-keyword">for</span> (<span class="hljs-keyword">let</span> i = <span class="hljs-number">0</span>; i &lt; the_animation.length; i++) {
   <span class="hljs-keyword">const</span> elements = the_animation[i];

    observer.observe(elements);
  }
</code></pre>
<p>This is how the page looks now:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/03/Animation2.gif" alt="Image" width="600" height="400" loading="lazy"></p>
<h3 id="heading-complete-javascript-code">Complete JavaScript Code</h3>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> the_animation = <span class="hljs-built_in">document</span>.querySelectorAll(<span class="hljs-string">'.animation'</span>)

<span class="hljs-keyword">const</span> observer = <span class="hljs-keyword">new</span> IntersectionObserver(<span class="hljs-function">(<span class="hljs-params">entries</span>) =&gt;</span> {
    entries.forEach(<span class="hljs-function">(<span class="hljs-params">entry</span>) =&gt;</span> {
        <span class="hljs-keyword">if</span> (entry.isIntersecting) {
            entry.target.classList.add(<span class="hljs-string">'scroll-animation'</span>)
        }
            <span class="hljs-keyword">else</span> {
                entry.target.classList.remove(<span class="hljs-string">'scroll-animation'</span>)
            }

    })
},
   { <span class="hljs-attr">threshold</span>: <span class="hljs-number">0.5</span>
   });
<span class="hljs-comment">//</span>
  <span class="hljs-keyword">for</span> (<span class="hljs-keyword">let</span> i = <span class="hljs-number">0</span>; i &lt; the_animation.length; i++) {
   <span class="hljs-keyword">const</span> elements = the_animation[i];

    observer.observe(elements);
  }
</code></pre>
<h2 id="heading-conclusion">Conclusion</h2>
<p>In this article, you have learnt about one of JavaScript's observer-based APIs, the Intersection Observer API. You have also successfully built a simple webpage to showcase scroll animations with the API.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Implement Reveal on Scroll in React using the Intersection Observer API ]]>
                </title>
                <description>
                    <![CDATA[ Are you looking for an elegant way to reveal content on your React website as users scroll down the page? Look no further than the Intersection Observer API. In this article, you’ll learn how to implement the reveal on scroll effect in React using In... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/reveal-on-scroll-in-react-using-the-intersection-observer-api/</link>
                <guid isPermaLink="false">66bb89176b3bd8d6bf25ae3b</guid>
                
                    <category>
                        <![CDATA[ animation ]]>
                    </category>
                
                    <category>
                        <![CDATA[ api ]]>
                    </category>
                
                    <category>
                        <![CDATA[ React ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ David Jaja ]]>
                </dc:creator>
                <pubDate>Thu, 23 Mar 2023 22:20:44 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2023/03/Group-107.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Are you looking for an elegant way to reveal content on your React website as users scroll down the page? Look no further than the Intersection Observer API.</p>
<p>In this article, you’ll learn how to implement the reveal on scroll effect in React using Intersection Observer. This will allow you to create stunning, dynamic user experiences that keep visitors engaged and coming back for more. </p>
<p>This step-by-step guide will help you understand this technique in no time, taking your React development skills to the next level.</p>
<h2 id="heading-prerequisites">Prerequisites</h2>
<ul>
<li>Fundamentals of HTML and CSS</li>
<li>Fundamentals of JavaScript and JavaScript’s Intersection Observer API</li>
<li>Fundamental knowledge of React</li>
<li>A code editor, a browser (preferably one that supports Java Script's Intersection API, like Google Chrome) and Node.js</li>
</ul>
<h2 id="heading-what-is-the-intersection-observer-api">What is the Intersection Observer API?</h2>
<p>Intersection Observer is a web-based API that enables developers to detect when a specific element intersects with another element or the viewport.</p>
<p>You can use this API to monitor any changes in the visibility of an element as it intersects with another element, or exits / enters the viewport.</p>
<h3 id="heading-how-the-intersection-observer-api-works">How the Intersection Observer API Works</h3>
<p>Intersection Observer first watches for an intersection (either between two elements or an element and the browser’s viewport). When it detects an intersection, the observer function fires a callback function that tells the code what to do next.</p>
<h2 id="heading-how-to-implement-the-intersection-observer-api-in-react">How to Implement the Intersection Observer API in React</h2>
<p>This section consists of three parts:</p>
<ol>
<li>Setting up your React environment</li>
<li>Adding boilerplates and styles</li>
<li>Implementing the review on scroll functionality</li>
</ol>
<h3 id="heading-how-to-set-up-your-react-environment">How to set up your React environment:</h3>
<p>First, you'll need to set up a React environment by running <code>npx create-react-app [your project name]</code>, either on your native terminal or an IDE’s terminal.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/03/001-npx-cra.png" alt="Image" width="600" height="400" loading="lazy">
<em>Command to create your React app</em></p>
<p>If you chose to use a native terminal, your next step will be opening that file with your preferred IDE. It should look something like this:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/03/002-after-cra.png" alt="Image" width="600" height="400" loading="lazy">
<em>Opening the file in your IDE</em></p>
<h3 id="heading-how-to-add-boilerplate-and-styles">How to add boilerplate and styles</h3>
<p>Next, clear all the default stylings and rid yourself of all the unnecessary files and imports for this project. This leaves your folder structure looking like this:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/03/003-after-clearing-unnecessary-things.png" alt="Image" width="600" height="400" loading="lazy">
<em>React app folder structure</em></p>
<p>For the <code>App</code> component, you'll create three child elements (<em>header</em>, <em>main</em> and <em>footer</em>). This is necessary because it gives you a better understanding of the reveal-on-scroll effect as you scroll in from the <em>header</em> and scroll out through the <em>footer.</em></p>
<pre><code class="lang-js">Import ‘./App.css’
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">App</span>(<span class="hljs-params"></span>)
</span>{  <span class="hljs-keyword">return</span> 
(    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"App"</span>&gt;</span>  
        <span class="hljs-tag">&lt;<span class="hljs-name">header</span>&gt;</span>This is the Header<span class="hljs-tag">&lt;/<span class="hljs-name">header</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">main</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"child-one"</span>&gt;</span>Child One<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"child-two"</span>&gt;</span>Child Two<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">main</span>&gt;</span>      
        <span class="hljs-tag">&lt;<span class="hljs-name">footer</span>&gt;</span>This is the Footer<span class="hljs-tag">&lt;/<span class="hljs-name">footer</span>&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>  );
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> App;
</code></pre>
<p>Then apply these styles in the App.css file to organise your app's layout.</p>
<pre><code class="lang-css"><span class="hljs-keyword">@import</span> url(<span class="hljs-string">"https://fonts.googleapis.com/css2?family=Edu+NSW+ACT+Foundation:wght@500&amp;display=swap"</span>);

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

<span class="hljs-selector-class">.App</span> {
  <span class="hljs-attribute">width</span>: <span class="hljs-number">100%</span>;
  <span class="hljs-attribute">height</span>: <span class="hljs-number">100%</span>;
  <span class="hljs-attribute">background</span>: <span class="hljs-number">#fff</span>;
  <span class="hljs-attribute">font-family</span>: <span class="hljs-string">"Edu NSW ACT Foundation"</span>, cursive;
}

<span class="hljs-selector-tag">body</span> {
  <span class="hljs-attribute">font-size</span>: <span class="hljs-number">50px</span>;
}

<span class="hljs-selector-tag">header</span>,
<span class="hljs-selector-tag">footer</span> {
  <span class="hljs-attribute">box-shadow</span>: <span class="hljs-number">3px</span> <span class="hljs-number">5px</span> <span class="hljs-number">5px</span> <span class="hljs-built_in">rgba</span>(<span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0.3</span>);
  <span class="hljs-attribute">height</span>: <span class="hljs-number">100vh</span>;
  <span class="hljs-attribute">margin-bottom</span>: <span class="hljs-number">50px</span>;
  <span class="hljs-attribute">display</span>: flex;
  <span class="hljs-attribute">justify-content</span>: center;
  <span class="hljs-attribute">align-items</span>: center;
}

<span class="hljs-selector-tag">footer</span> {
  <span class="hljs-attribute">margin-top</span>: <span class="hljs-number">50px</span>;
  <span class="hljs-attribute">box-shadow</span>: -<span class="hljs-number">3px</span> -<span class="hljs-number">5px</span> <span class="hljs-number">5px</span> <span class="hljs-built_in">rgba</span>(<span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0.3</span>);
}

<span class="hljs-selector-tag">main</span> {
  <span class="hljs-attribute">box-shadow</span>: <span class="hljs-number">3px</span> <span class="hljs-number">5px</span> <span class="hljs-number">5px</span> <span class="hljs-built_in">rgba</span>(<span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0.3</span>), -<span class="hljs-number">3px</span> -<span class="hljs-number">5px</span> <span class="hljs-number">5px</span> <span class="hljs-built_in">rgba</span>(<span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0.3</span>);
  <span class="hljs-attribute">height</span>: <span class="hljs-number">100vh</span>;
  <span class="hljs-attribute">display</span>: flex;
  <span class="hljs-attribute">align-items</span>: center;
  <span class="hljs-attribute">justify-content</span>: center;
  <span class="hljs-attribute">padding</span>: <span class="hljs-number">50px</span>;
  <span class="hljs-attribute">gap</span>: <span class="hljs-number">50px</span>;
  <span class="hljs-attribute">overflow</span>: hidden;
}

<span class="hljs-selector-tag">main</span> <span class="hljs-selector-tag">div</span> {
  <span class="hljs-attribute">flex</span>: <span class="hljs-number">1</span>;
  <span class="hljs-attribute">height</span>: <span class="hljs-number">80%</span>;
  <span class="hljs-attribute">border</span>: <span class="hljs-number">2px</span> solid <span class="hljs-number">#999</span>;
  <span class="hljs-attribute">display</span>: flex;
  <span class="hljs-attribute">justify-content</span>: center;
  <span class="hljs-attribute">align-items</span>: center;
  <span class="hljs-attribute">border-radius</span>: <span class="hljs-number">10px</span>;
  <span class="hljs-attribute">Transition</span>: all ease-in <span class="hljs-number">1s</span>;
}

<span class="hljs-selector-class">.slide-in</span> {
  <span class="hljs-attribute">transform</span>: <span class="hljs-built_in">translateX</span>(<span class="hljs-number">0</span>) <span class="hljs-meta">!important</span>;
}
</code></pre>
<p>Your project should look like this currently:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/03/001-Initial-styling.gif" alt="Image" width="600" height="400" loading="lazy">
<em>Layout after applying styles</em></p>
<h3 id="heading-how-to-implement-the-review-on-scroll-functionality">How to implement the review on scroll functionality</h3>
<p>First, you need to create a state that holds the current intersecting value – that is, if the monitored element is intersecting something or not.</p>
<pre><code class="lang-js"><span class="hljs-keyword">import</span> { useState} <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>;
<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">test</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> [isIntersecting, setIsIntersecting] = useState(<span class="hljs-literal">false</span>);
</code></pre>
<p>The initial value of the state is set to <em>false</em>, and changes to <em>true</em> when an intersection occurs.</p>
<p>Next, you create a reference using the <code>useRef</code> hook, which you will then attach to the element you want to reference. This hook is used to store a reference to a DOM element (similar to what you would get with <code>document.querySelector</code>), allowing you to access and manipulate the element directly when needed.</p>
<pre><code class="lang-js"><span class="hljs-keyword">import</span> { useState, useRef } <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>;
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">App</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> [isIntersecting, setIsIntersecting] = useState(<span class="hljs-literal">false</span>);

  <span class="hljs-keyword">const</span> ref = useRef(<span class="hljs-literal">null</span>);

  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"App"</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">header</span>&gt;</span>This is the Header<span class="hljs-tag">&lt;/<span class="hljs-name">header</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">main</span> <span class="hljs-attr">ref</span>=<span class="hljs-string">{ref}</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"child-one"</span>&gt;</span>Child One<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"child-two"</span>&gt;</span>Child Two<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">main</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">footer</span>&gt;</span>This is the Footer<span class="hljs-tag">&lt;/<span class="hljs-name">footer</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  );
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> App;
</code></pre>
<p>Next, you use a <code>useEffect</code> hook to create an intersection observer instance that watches for intersections.</p>
<pre><code class="lang-js"><span class="hljs-keyword">import</span> { useState, useRef, useEffect} <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>; 

useEffect(<span class="hljs-function">() =&gt;</span> {
    <span class="hljs-keyword">const</span> observer = <span class="hljs-keyword">new</span> IntersectionObserver();
  }, []);
</code></pre>
<p>After that, you'll pass in a callback function that updates the intersecting state.</p>
<pre><code class="lang-js"> useEffect(<span class="hljs-function">() =&gt;</span> {
    <span class="hljs-keyword">const</span> observer = <span class="hljs-keyword">new</span> IntersectionObserver(
      <span class="hljs-function">(<span class="hljs-params">[entry]</span>) =&gt;</span> {
        setIsIntersecting(entry.isIntersecting);
      }
    );
  }, []);
</code></pre>
<p>Keep in mind that we deconstructed the entries array to get the first value, that is the first intersection.</p>
<p>Next, you provide an options object as the second argument to the <code>IntersectionObserver</code> function. </p>
<p>The options object can have several properties, including the <code>rootMargin</code> property. The <code>rootMargin</code> value defines the margins around the observed element, effectively expanding or contracting its bounding box. The observer function triggers when the adjusted bounding box enters or exits the intersection with the specified root element.</p>
<pre><code class="lang-js">useEffect(<span class="hljs-function">() =&gt;</span> {
    <span class="hljs-keyword">const</span> observer = <span class="hljs-keyword">new</span> IntersectionObserver(
      <span class="hljs-function">(<span class="hljs-params">[entry]</span>) =&gt;</span> {
        setIsIntersecting(entry.isIntersecting);
      },
      { <span class="hljs-attr">rootMargin</span>: <span class="hljs-string">"-300px"</span> }
    );
  }, []);
</code></pre>
<p><strong>Note</strong>: It is important to note that if you specify a negative value for <code>rootMargin</code>, the observer function will fire when the observed element is already partially visible. For example, a value of <code>-300px</code> means that the observer function will trigger when 300 pixels of the observed element have come into view.</p>
<p>Your next step is to call the <code>observe</code> method on the <code>observer</code> to indicate the current element you’re observing.</p>
<pre><code class="lang-js">useEffect(<span class="hljs-function">() =&gt;</span> {
    <span class="hljs-keyword">const</span> observer = <span class="hljs-keyword">new</span> IntersectionObserver(
      <span class="hljs-function">(<span class="hljs-params">[entry]</span>) =&gt;</span> {
        setIsIntersecting(entry.isIntersecting);
      },
    );
    observer.observe(ref.current);
  }, []);
</code></pre>
<p>With this, you’ve set up your observer instance. All that’s left in this hook is to create a cleanup function that terminates the observation when the observed element unmounts.</p>
<pre><code class="lang-js"> useEffect(<span class="hljs-function">() =&gt;</span> {
    <span class="hljs-keyword">const</span> observer = <span class="hljs-keyword">new</span> IntersectionObserver(<span class="hljs-function">(<span class="hljs-params">[entry]</span>) =&gt;</span> {
      setIsIntersecting(entry.isIntersecting);
    });
    observer.observe(ref.current);
    <span class="hljs-keyword">return</span> <span class="hljs-function">() =&gt;</span> observer.disconnect();
  }, []);
</code></pre>
<p>Let’s test to see if our observer function works properly by logging the current value of <code>isIntersecting</code> to the console.</p>
<pre><code class="lang-js">useEffect(<span class="hljs-function">() =&gt;</span> {
    <span class="hljs-keyword">const</span> observer = <span class="hljs-keyword">new</span> IntersectionObserver(<span class="hljs-function">(<span class="hljs-params">[entry]</span>) =&gt;</span> {
      setIsIntersecting(entry.isIntersecting);
    });
    <span class="hljs-built_in">console</span>.log(isIntersecting);
    observer.observe(ref.current);
    <span class="hljs-keyword">return</span> <span class="hljs-function">() =&gt;</span> observer.disconnect();
  }, []);
</code></pre>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/03/002-Test-intersection.gif" alt="Image" width="600" height="400" loading="lazy">
<em>Testing for intersections with the browser console</em></p>
<p>As you can see, when you first load the page, the value of <code>isIntersecting</code> is <em>false</em> because no intersection has occurred. As you scroll down the page and see your target element, the value changes to <em>true</em>, and when you leave the element the value changes back to <em>false</em>. </p>
<p>To achieve the desired reveal-on-scroll effect, it is crucial to first translate both child divs out of the viewport. This will allow you to bring them back when <code>isIntersection</code> is <em>true</em>, that is during the intersection, which is the key step in creating the effect.</p>
<pre><code class="lang-css"><span class="hljs-selector-tag">main</span> <span class="hljs-selector-tag">div</span><span class="hljs-selector-pseudo">:first-child</span> {
  <span class="hljs-attribute">transform</span>: <span class="hljs-built_in">translateX</span>(-<span class="hljs-number">150%</span>);
  <span class="hljs-attribute">opacity</span>: <span class="hljs-number">0</span>;
}
<span class="hljs-selector-tag">main</span> <span class="hljs-selector-tag">div</span><span class="hljs-selector-pseudo">:last-child</span> {
  <span class="hljs-attribute">transform</span>: <span class="hljs-built_in">translateX</span>(<span class="hljs-number">150%</span>);
  <span class="hljs-attribute">opacity</span>: <span class="hljs-number">0</span>;
}
</code></pre>
<p>Next, you use a second <code>useEffect</code> hook to handle the logic of bringing our child divs into view. You first check if there is an intersection:</p>
<pre><code class="lang-js"> useEffect(<span class="hljs-function">() =&gt;</span> {
    <span class="hljs-keyword">if</span> (isIntersecting) {

    }
  }, []);
</code></pre>
<p>Then you target all the child elements inside the observed element, loop over them, and add a CSS class that reveals them.</p>
<pre><code class="lang-css"><span class="hljs-selector-class">.slide-in</span> {
  <span class="hljs-attribute">transform</span>: <span class="hljs-built_in">translateX</span>(<span class="hljs-number">0</span>) <span class="hljs-meta">!important</span>;
  <span class="hljs-attribute">opacity</span>: <span class="hljs-number">1</span> <span class="hljs-meta">!important</span>;
}
</code></pre>
<pre><code class="lang-js"> useEffect(<span class="hljs-function">() =&gt;</span> {
    <span class="hljs-keyword">if</span> (isIntersecting) {
      ref.current.querySelectorAll(<span class="hljs-string">"div"</span>).forEach(<span class="hljs-function">(<span class="hljs-params">el</span>) =&gt;</span> {
        el.classList.add(<span class="hljs-string">"slide-in"</span>);
      });
    }
  }, [isIntersecting]);
</code></pre>
<p><strong>Note</strong>: Since a change in the value of <code>isIntersecting</code> causes the <code>useEffect</code> hook to re-render, we pass it as a dependency in the dependency array.</p>
<p>Taking a look at what you’ve achieved so far:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/03/003-Initial-intersection.gif" alt="Image" width="600" height="400" loading="lazy">
<em>Initial reveal-on-scroll effect achieved</em></p>
<p>And with that, you’ve implemented reveal on scroll functionality – kudos!<br>All that’s left to do is to make the child elements leave the viewport once there’s no longer an intersection.</p>
<pre><code class="lang-js">useEffect(<span class="hljs-function">() =&gt;</span> {
    <span class="hljs-keyword">if</span> (isIntersecting) {
      ref.current.querySelectorAll(<span class="hljs-string">"div"</span>).forEach(<span class="hljs-function">(<span class="hljs-params">el</span>) =&gt;</span> {
        el.classList.add(<span class="hljs-string">"slide-in"</span>);
      });
    } <span class="hljs-keyword">else</span> {
      ref.current.querySelectorAll(<span class="hljs-string">"div"</span>).forEach(<span class="hljs-function">(<span class="hljs-params">el</span>) =&gt;</span> {
        el.classList.remove(<span class="hljs-string">"slide-in"</span>);
      });
    }
  }, [isIntersecting]);
</code></pre>
<p>This leaves us with the final effect:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/03/004-Final-intersection.gif" alt="Image" width="600" height="400" loading="lazy">
<em>The final reveal-on-scroll effect achieved</em></p>
<p>The final full code is displayed below:</p>
<pre><code class="lang-js"><span class="hljs-keyword">import</span> <span class="hljs-string">"./App.css"</span>;

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

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">App</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> [isIntersecting, setIsIntersecting] = useState(<span class="hljs-literal">false</span>);
  <span class="hljs-keyword">const</span> ref = useRef(<span class="hljs-literal">null</span>);

  useEffect(<span class="hljs-function">() =&gt;</span> {
    <span class="hljs-keyword">const</span> observer = <span class="hljs-keyword">new</span> IntersectionObserver(
      <span class="hljs-function">(<span class="hljs-params">[entry]</span>) =&gt;</span> {
        setIsIntersecting(entry.isIntersecting);
      },
      { <span class="hljs-attr">rootMargin</span>: <span class="hljs-string">"-300px"</span> }
    );
    <span class="hljs-built_in">console</span>.log(isIntersecting);
    observer.observe(ref.current);

    <span class="hljs-keyword">return</span> <span class="hljs-function">() =&gt;</span> observer.disconnect();
  }, [isIntersecting]);

  useEffect(<span class="hljs-function">() =&gt;</span> {
    <span class="hljs-keyword">if</span> (isIntersecting) {
      ref.current.querySelectorAll(<span class="hljs-string">"div"</span>).forEach(<span class="hljs-function">(<span class="hljs-params">el</span>) =&gt;</span> {
        el.classList.add(<span class="hljs-string">"slide-in"</span>);
      });
    } <span class="hljs-keyword">else</span> {
      ref.current.querySelectorAll(<span class="hljs-string">"div"</span>).forEach(<span class="hljs-function">(<span class="hljs-params">el</span>) =&gt;</span> {
        el.classList.remove(<span class="hljs-string">"slide-in"</span>);
      });
    }
  }, [isIntersecting]);

  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"App"</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">header</span>&gt;</span>This is the Header<span class="hljs-tag">&lt;/<span class="hljs-name">header</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">main</span> <span class="hljs-attr">ref</span>=<span class="hljs-string">{ref}</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"child-one"</span>&gt;</span>Child One<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"child-two"</span>&gt;</span>Child Two<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">main</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">footer</span>&gt;</span>This is the Footer<span class="hljs-tag">&lt;/<span class="hljs-name">footer</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  );
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> App;
</code></pre>
<h2 id="heading-other-options">Other Options</h2>
<p>It's worth mentioning that although using the Intersection Observer for scroll animations is effective, there are newer approaches to implementing reveal-on-scroll animations in React. These approaches include the use of animation libraries such as <a target="_blank" href="https://www.framer.com/motion/">Framer Motion</a> and <a target="_blank" href="https://greensock.com/gsap/">GSAP</a>. </p>
<p>These libraries provide a straightforward way for developers to create smooth and engaging animations while ensuring high performance.</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>The Intersection Observer API is an effective tool for developing engaging user interfaces in web development. You can add an extra layer of interactivity to your web applications by implementing reveal-on-scroll effects in React with this API. </p>
<p>We covered the fundamentals of using the Intersection Observer API in React, from setting up your environment to adding styles and functionality in this tutorial. </p>
<p>Going forward, you can take the knowledge and skills you gained from this tutorial and boost your web development knowledge to create stunning, dynamic user interfaces that keep your users coming back for more.</p>
<h3 id="heading-project-links">Project Links</h3>
<ul>
<li>Live Site URL: <a target="_blank" href="https://react-intersection-api-article.netlify.app/">Netlify</a></li>
<li>Code Repository: <a target="_blank" href="https://github.com/Daiveedjay/React-Intersection-API-article">GitHub</a></li>
</ul>
<h3 id="heading-other-resources">Other Resources</h3>
<p>Since this article isn’t centered around the full workings of the Intersection Observer API, here are a couple of resources which can help you get a better understanding.</p>
<ul>
<li><a target="_blank" href="https://daiveedjay.hashnode.dev/implementing-image-lazy-loading-to-improve-website-performance-using-javascript">Implementing image lazy loading to improve website performance using JavaScript</a></li>
<li><a target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/API/Intersection_Observer_API">Intersection Observer API</a></li>
<li><a target="_blank" href="https://blog.webdevsimplified.com/2022-01/intersection-observer/">JavaScript Intersection Observer Ultimate Guide</a></li>
</ul>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Animate Your React Apps with 1 Line of Code ]]>
                </title>
                <description>
                    <![CDATA[ Animations have the powerful ability to turn a boring, static application into a more dynamic, memorable experience for your users.  In general, animations can be quite difficult to set up, especially if you intend to animate multiple components in y... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/animate-react-apps/</link>
                <guid isPermaLink="false">66d0374cdcd3a41034854bb4</guid>
                
                    <category>
                        <![CDATA[ animation ]]>
                    </category>
                
                    <category>
                        <![CDATA[ React ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Reed ]]>
                </dc:creator>
                <pubDate>Thu, 15 Sep 2022 19:56:57 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2022/09/mugshotbot.com_customize_color-red-image-9129875b-mode-dark-pattern-topography-theme-two_up-url-https___freecodecamp.org.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Animations have the powerful ability to turn a boring, static application into a more dynamic, memorable experience for your users. </p>
<p>In general, animations can be quite difficult to set up, especially if you intend to animate multiple components in your app. </p>
<p>In this tutorial, we will see how to implement virtually every common animation in your React apps with one line of code using the library <strong>AutoAnimate</strong>.</p>
<h2 id="heading-why-you-should-use-autoanimate">Why You Should Use AutoAnimate</h2>
<p>If you're building a React application, there are many powerful animation libraries you can choose, such as Framer Motion.</p>
<p>The downside of most of these libraries (as well as plain CSS) is that they require quite a bit of code to make your animations work. You traditionally have to specify:</p>
<ol>
<li>The CSS properties you want to animate</li>
<li>The duration over which you want the animation to be performed</li>
<li>An easing function that determines how the animation progresses through the duration of each cycle</li>
</ol>
<p>AutoAnimate removes to need to specify <strong>any</strong> of these things.</p>
<p>The power of AutoAnimate is that it allows you to animate your entire app using a using a single function called <code>autoAnimate</code>.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/09/Screen-Shot-2022-09-15-at-11.37.45-AM.png" alt="Image" width="600" height="400" loading="lazy">
<em>The AutoAnimate animation library</em></p>
<h2 id="heading-how-autoanimate-works">How AutoAnimate Works</h2>
<p><code>autoAnimate</code> takes one argument: a reference to the parent element which you would like to animate. </p>
<p>The way the library works is that the parent element will be "auto animated" along with any of its immediate children.</p>
<p>Animations take place whenever one of three events occurs to this parent element:</p>
<p>If a child element is <strong>added</strong>, <strong>removed</strong>, or <strong>moved</strong> around.</p>
<p>We're going to look at how you can use AutoAnimate with three examples: an expandable component, list component and a grid component.</p>
<h2 id="heading-how-to-use-autoanimate">How to Use AutoAnimate</h2>
<p>There are two steps to start using auto animate:</p>
<ol>
<li>Install it in your project using either yarn or NPM </li>
</ol>
<pre><code class="lang-bash">npm install @formkit/auto-animate
</code></pre>
<ol>
<li>Import the auto animate function from the library itself</li>
</ol>
<pre><code class="lang-js"><span class="hljs-keyword">import</span> autoAnimate <span class="hljs-keyword">from</span> <span class="hljs-string">'@formkit/auto-animate'</span>
</code></pre>
<p>This tutorial covers how to use AutoAnimate in React applications, but you can use it in virtually any JavaScript project (including Svelte, Vue and Vanilla JS).</p>
<p>To animate any parent element you just need to pass a reference of the element to the function.</p>
<pre><code class="lang-js"><span class="hljs-keyword">import</span> { useEffect, useRef } <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Component</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> parentRef = useRef(<span class="hljs-literal">null</span>)

  useEffect(<span class="hljs-function">() =&gt;</span> {
    <span class="hljs-keyword">if</span> (parentRef.current) {
      autoAnimate(parentRef.current);   
    }
  }, [parent])

  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">ref</span>=<span class="hljs-string">{parentRef}</span>&gt;</span>
    // ...
  )
}</span>
</code></pre>
<p>We can see how this works on simple expandable components such as an FAQ (Frequently Asked Questions) component. </p>
<p>Let's say we want our users to be able to click on a div and expand it to show some more text. </p>
<p>First, we create a div with some text to display in its initial state (<code>Show More</code> ) as well as some text to reveal when clicked.</p>
<p>To animate the text opening, we use the <code>useRef</code> hook to reference the parent element and then pass that reference to the auto animate function. </p>
<div class="embed-wrapper">
        <iframe width="100%" height="350" src="https://codesandbox.io/embed/epic-lamport-5y9uwk?fontsize=14&amp;hidenavigation=1&amp;theme=dark" style="aspect-ratio: 16 / 9; width: 100%; height: auto;" title="CodeSandbox embed" allow="geolocation; microphone; camera; midi; vr; accelerometer; gyroscope; payment; ambient-light-sensor; encrypted-media; usb" sandbox="allow-modals allow-forms allow-popups allow-scripts allow-same-origin" loading="lazy"></iframe></div>
<p>And instantly, we have a much more engaging, smoothly animated component.</p>
<h2 id="heading-how-to-animate-lists-with-autoanimate">How to Animate Lists with AutoAnimate</h2>
<p>Another great use case for auto animate is with a list component. </p>
<p>Let's say we are building a todo application and we would like to animate new items that are added to the list.</p>
<pre><code class="lang-js"><span class="hljs-keyword">import</span> { useState } <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>
<span class="hljs-keyword">import</span> autoAnimate <span class="hljs-keyword">from</span> <span class="hljs-string">"@formkit/auto-animate"</span>

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">App</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> [items, setItems] = useState([<span class="hljs-string">"Buy Gas"</span>, <span class="hljs-string">"Do Laundry"</span>])

  <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">addItem</span>(<span class="hljs-params"></span>) </span>{
    <span class="hljs-keyword">const</span> item = <span class="hljs-string">"Go To Store"</span>
    setItems([...items, item])
  }

  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">ul</span> <span class="hljs-attr">ref</span>=<span class="hljs-string">{parent}</span>&gt;</span>
        {items.map((item) =&gt; (
          <span class="hljs-tag">&lt;<span class="hljs-name">li</span> <span class="hljs-attr">key</span>=<span class="hljs-string">{item}</span>&gt;</span>{item}<span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
        ))}
      <span class="hljs-tag">&lt;/<span class="hljs-name">ul</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">onClick</span>=<span class="hljs-string">{addItem}</span>&gt;</span>Add Todo<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
    <span class="hljs-tag">&lt;/&gt;</span></span>
  )
}
</code></pre>
<p>In this example, we have a list of to do items, and whenever we click a button it adds a new item to our list. </p>
<p>If we want to animate it, we can repeat the same steps as before but we add a reference to the parent element (in this case, an unordered list).</p>
<div class="embed-wrapper">
        <iframe width="100%" height="350" src="https://codesandbox.io/embed/unruffled-night-ugucy0?fontsize=14&amp;hidenavigation=1&amp;theme=dark" style="aspect-ratio: 16 / 9; width: 100%; height: auto;" title="CodeSandbox embed" allow="geolocation; microphone; camera; midi; vr; accelerometer; gyroscope; payment; ambient-light-sensor; encrypted-media; usb" sandbox="allow-modals allow-forms allow-popups allow-scripts allow-same-origin" loading="lazy"></iframe></div>
<p>Whenever we click the button to add a new item to our list, now each to do is inserted into the list in a smooth manner, animating both its position and opacity.</p>
<h2 id="heading-how-to-customize-animations">How to Customize Animations</h2>
<p>AutoAnimate is intended to be an all-in-one solution for animations that does not require configuration, but it does permit us to customize values such as the duration and when the animation plays.</p>
<p>For greater control over our animations, we can use the <code>useAutoAnimate</code> which can be imported in this way:</p>
<pre><code class="lang-js"><span class="hljs-keyword">import</span> { useAutoAnimate } <span class="hljs-keyword">from</span> <span class="hljs-string">"@formkit/auto-animate/react"</span>;
</code></pre>
<p>Just like any React hook, it is called at the top of any React component in which we want to use it.</p>
<p>The benefit of this hook is that we no longer need to use the <code>useRef</code> hook. Instead, the hook returns it as well as a function that allows us to control whether we want to animate the parent element or not.</p>
<pre><code class="lang-js"><span class="hljs-keyword">import</span> { useAutoAnimate } <span class="hljs-keyword">from</span> <span class="hljs-string">"@formkit/auto-animate/react"</span>;

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">App</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> [parent, enable] = useAutoAnimate({ <span class="hljs-attr">duration</span>: <span class="hljs-number">500</span> });
  <span class="hljs-keyword">const</span> [isEnabled, setIsEnabled] = useState(<span class="hljs-literal">true</span>);

  <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">toggleEnabled</span>(<span class="hljs-params"></span>) </span>{
    enable(!isEnabled);
    setIsEnabled(!isEnabled);
  }

   <span class="hljs-comment">// ...</span>
 }
</code></pre>
<p>Let's say we're using a form to add a new item to this grid and we want to smoothly push all the others out of the way.</p>
<p>AutoAnimate once again makes this very easy, but in this case, we will use the <code>useAutoAnimate</code> hook to perform the animation after half a second. To do so, we can use the duration property.</p>
<pre><code class="lang-jsx">  <span class="hljs-keyword">const</span> [parent, enable] = useAutoAnimate({ <span class="hljs-attr">duration</span>: <span class="hljs-number">500</span> });
</code></pre>
<p>As you see, it handles both the animation in of the new card being added as well as the animation of pushing all the other cards aside.</p>
<div class="embed-wrapper">
        <iframe width="100%" height="350" src="https://codesandbox.io/embed/boring-haze-k7tdjr?fontsize=14&amp;hidenavigation=1&amp;theme=dark" style="aspect-ratio: 16 / 9; width: 100%; height: auto;" title="CodeSandbox embed" allow="geolocation; microphone; camera; midi; vr; accelerometer; gyroscope; payment; ambient-light-sensor; encrypted-media; usb" sandbox="allow-modals allow-forms allow-popups allow-scripts allow-same-origin" loading="lazy"></iframe></div>
<p>And that's it! Now you can use this helpful library to easily animate your React apps.</p>
<h2 id="heading-become-a-professional-react-developer">Become a Professional React Developer</h2>
<p>React is hard. You shouldn't have to figure it out yourself.</p>
<p>I've put everything I know about React into a single course, to help you reach your goals in record time:</p>
<p><a target="_blank" href="https://www.thereactbootcamp.com"><strong>Introducing: The React Bootcamp</strong></a></p>
<p><strong>It’s the one course I wish I had when I started learning React.</strong></p>
<p>Click below to try the React Bootcamp for yourself:</p>
<p><a target="_blank" href="https://www.thereactbootcamp.com"><img src="https://reedbarger.nyc3.digitaloceanspaces.com/reactbootcamp/react-bootcamp-cta-alt.png" alt="Click to join the React Bootcamp" width="600" height="400" loading="lazy"></a>
<em>Click to get started</em></p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Use the Rough Notation Library to Animate Your Website ]]>
                </title>
                <description>
                    <![CDATA[ I love animating websites. It's so fun when you just look at a site, and there are cool animations that make everything look pretty. Getting started with an animation library does not have to be hard. Anyone can add a bit of animation to their site r... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-add-animation-to-your-site-with-rough-notation/</link>
                <guid isPermaLink="false">66d4608ba326133d12440a4b</guid>
                
                    <category>
                        <![CDATA[ animation ]]>
                    </category>
                
                    <category>
                        <![CDATA[ JavaScript ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Libraries ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Web Development ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Njong Emy ]]>
                </dc:creator>
                <pubDate>Tue, 02 Aug 2022 16:52:13 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2022/08/png_20220803_195955_0000.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>I love animating websites. It's so fun when you just look at a site, and there are cool animations that make everything look pretty.</p>
<p>Getting started with an animation library does not have to be hard. Anyone can add a bit of animation to their site regardless of whether they are good working with the front end or not.</p>
<p>Let me show you how you can get started.</p>
<h1 id="heading-what-is-rough-notation">What is Rough Notation?</h1>
<p>Rough notation is lightweight yet amazing JavaScript animation library that you can use to get started with animations pretty quickly. And it is open source!</p>
<p>The docs are pretty straightforward, which is one reason it's a great animation library to start with.</p>
<p>In this article, I'll take you through the basic steps to get started with Rough Notation, and we'll build a pretty small site with some animations.</p>
<p>If you like using the library, check out their super repository. Give it a star, and if you love this article, shout them out! (This isn't sponsored. I just love the library :))</p>
<p>You can <a target="_blank" href="https://github.com/rough-stuff/rough-notation">check out the Rough Notation docs here</a>.</p>
<h2 id="heading-lets-get-animating">Let's Get Animating</h2>
<h3 id="heading-how-to-code-the-htmlcss">How to Code the HTML/CSS</h3>
<p>We can't animate something we don't see. So to start, we'll create a pretty simple static page with some minimal HTML and CSS.</p>
<p>For now, our HTML will just look bland. Nothing much going on. Just a nicely centered thing with a Poppins font going on.</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"main"</span>&gt;</span>

        <span class="hljs-tag">&lt;<span class="hljs-name">header</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">h1</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"header"</span>&gt;</span>Aloha. Hello. Salut.<span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">header</span>&gt;</span>

        <span class="hljs-tag">&lt;<span class="hljs-name">main</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>Today, we will animate this with <span class="hljs-tag">&lt;<span class="hljs-name">scan</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"rough-notation"</span>&gt;</span>Rough Notation<span class="hljs-tag">&lt;/<span class="hljs-name">scan</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>

            <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>This is a pretty simple site. If you love this, check Rough Notation out on <span class="hljs-tag">&lt;<span class="hljs-name">scan</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"link"</span>&gt;</span>Github<span class="hljs-tag">&lt;/<span class="hljs-name">scan</span>&gt;</span>. They are open source, and they are amazing!<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>

            <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Maiores omnis molestias voluptas, odit laboriosam esse distinctio provident pariatur accusamus cum?<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>

            <span class="hljs-tag">&lt;<span class="hljs-name">h2</span>&gt;</span>A bit about Rough Notation<span class="hljs-tag">&lt;/<span class="hljs-name">h2</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">ul</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"list"</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">li</span>&gt;</span>It's open source.<span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">li</span>&gt;</span>It's easy to start with.<span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">li</span>&gt;</span>I love it!<span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
            <span class="hljs-tag">&lt;/<span class="hljs-name">ul</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">main</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
</code></pre>
<p>In the above code, notice the classes I have added to some of the elements. This is how we select what elements to animate.</p>
<p>Our CSS itself is bare, but here is how it is and what our page looks like:</p>
<pre><code class="lang-css"><span class="hljs-keyword">@import</span> url(<span class="hljs-string">'https://fonts.googleapis.com/css2?family=Poppins:wght@300&amp;display=swap'</span>);
*{
    <span class="hljs-attribute">box-sizing</span>: border-box;
    <span class="hljs-attribute">margin</span>: <span class="hljs-number">0</span>;
    <span class="hljs-attribute">padding</span>: <span class="hljs-number">0</span>;
}
<span class="hljs-selector-tag">body</span>{
    <span class="hljs-attribute">font-family</span>: <span class="hljs-string">'Poppins'</span>, sans-serif;
}
<span class="hljs-selector-class">.main</span>{
    <span class="hljs-attribute">display</span>: flex;
    <span class="hljs-attribute">justify-content</span>: center;
    <span class="hljs-attribute">align-items</span>: center;
    <span class="hljs-attribute">flex-direction</span>: column;
    <span class="hljs-attribute">padding</span>: <span class="hljs-number">10px</span>;
    <span class="hljs-attribute">margin</span>: <span class="hljs-number">40px</span>;
}
<span class="hljs-selector-tag">h1</span>{
    <span class="hljs-attribute">margin-bottom</span>: <span class="hljs-number">10px</span>;
}
<span class="hljs-selector-tag">p</span>{
    <span class="hljs-attribute">margin-bottom</span>: <span class="hljs-number">15px</span>;
}
<span class="hljs-selector-tag">ul</span>{
    <span class="hljs-attribute">margin</span>: <span class="hljs-number">20px</span>;
}
</code></pre>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/08/Screenshot-from-2022-08-01-17-31-32.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>Screenshot of how our bare static page looks. There is an h1 header that says 'Aloha. Hello. Salut.' A few other paragraphs make up the page and there is an unordered list that states three little facts about Rough Notation.</em></p>
<h3 id="heading-lets-add-some-javascript">Let's Add Some JavaScript</h3>
<p>Hold on, this is the juicy part! For our animations to take any kind of effect, we need a JavaScript file. Just create one, and link it to your HTML like you would normally do.</p>
<p>Now let's see how Rough Notation works.</p>
<p>The docs offer a few ways to add the library to our projects. For the sake of simplicity, we will load the ES module directly.</p>
<p><a target="_blank" href="https://github.com/rough-stuff/rough-notation">Check out the repo and the docs here</a>.</p>
<p>So essentially, we will add the an extra script tag to our HTML so that it looks like this:</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">script</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"module"</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"https://unpkg.com/rough-notation?module"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span>
</code></pre>
<p>Now that Rough Notation is partially present in our project, we can dig into our JavaScript file, and import it. The first line of our JavaScript doc would look like this:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> { annotate } <span class="hljs-keyword">from</span> <span class="hljs-string">'rough-notation'</span>;
</code></pre>
<p>Now that Rough Notation is fully set up, let's grab what we want to animate from the page. Based on what elements we added classes to, we would have the following:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> header = <span class="hljs-built_in">document</span>.querySelector(<span class="hljs-string">'.header'</span>);
<span class="hljs-keyword">const</span> roughNotation = <span class="hljs-built_in">document</span>.querySelector(<span class="hljs-string">'.rough-notation'</span>);
<span class="hljs-keyword">const</span> link = <span class="hljs-built_in">document</span>.querySelector(<span class="hljs-string">'.link'</span>);
<span class="hljs-keyword">const</span> list = <span class="hljs-built_in">document</span>.querySelector(<span class="hljs-string">'.list'</span>);
</code></pre>
<p>The next step is what will bring our page to life. Say, I wanted to highlight the header a light pink color. I would write this code:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> annotation = annotate(header, { <span class="hljs-attr">type</span>: <span class="hljs-string">'highlight'</span> , <span class="hljs-attr">color</span>:<span class="hljs-string">'pink'</span>});
annotation.show();
</code></pre>
<p>We assign the variable annotation to a function called <code>annotate</code>. The annotate function takes two parameters – the element we want to annotate, and an object.</p>
<p>The object can take in a few attributes. In this case we have two: the type of annotation we want on the header, and the color.</p>
<p>And just to mention a few other types of annotations that we can do:</p>
<ul>
<li><p>Highlight</p>
</li>
<li><p>Circle</p>
</li>
<li><p>Underline</p>
</li>
<li><p>Brackets</p>
</li>
<li><p>Box</p>
</li>
<li><p>Strike-through</p>
</li>
<li><p>Crossed-off</p>
</li>
</ul>
<p>Back to our header animation. The last line is <code>annotation.show()</code> which just basically displays our animation.</p>
<p>If we save our page, and check our browser, nothing happens. It was supposed to work (according to the docs), but we get nothing.</p>
<p>I found a solution to the problem on a YouTube video, and in order for us to make the animation come to life, we have to adjust the import line in our JavaScript file.</p>
<p>So you can update it like this:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> { annotate } <span class="hljs-keyword">from</span> <span class="hljs-string">"https://unpkg.com/rough-notation?module"</span>;
</code></pre>
<p>If you are like me, and love opening issues to complain (just kidding) about open source projects, feel free to raise an issue on the Rough Notation repository if the animation doesn't work for you either. But only open an issue if no one has beat you to it yet. So do check recent open and closed issues first. May the best issue opener win :)</p>
<p>If you refresh after fixing the problem we had, our header gets a nice pink highlight. You see it nicely swooshing across the page.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/08/Screenshot-from-2022-08-01-18-24-31.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>Screenshot of our site now, with the header highlighted in pink.</em></p>
<p>Nice and pretty, right?</p>
<p>Let's go ahead and add a few more animations:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> annotation = annotate(header, { <span class="hljs-attr">type</span>: <span class="hljs-string">'highlight'</span> , <span class="hljs-attr">color</span>:<span class="hljs-string">'pink'</span>});
<span class="hljs-keyword">const</span> annotation2 = annotate(roughNotation, {<span class="hljs-attr">type</span>:<span class="hljs-string">'circle'</span>, <span class="hljs-attr">color</span>:<span class="hljs-string">'yellow'</span>, <span class="hljs-attr">padding</span>:<span class="hljs-number">7</span>});
<span class="hljs-keyword">const</span> annotation3 = annotate(link, { <span class="hljs-attr">type</span>: <span class="hljs-string">'box'</span> , <span class="hljs-attr">color</span>:<span class="hljs-string">'blue'</span>, <span class="hljs-attr">padding</span>:<span class="hljs-number">7</span>});
<span class="hljs-keyword">const</span> annotation4 = annotate(list, { <span class="hljs-attr">type</span>: <span class="hljs-string">'bracket'</span> , <span class="hljs-attr">color</span>:<span class="hljs-string">'red'</span>, <span class="hljs-attr">brackets</span>:[<span class="hljs-string">'left'</span>, <span class="hljs-string">'right'</span>], <span class="hljs-attr">strokeWidth</span>:<span class="hljs-number">5</span>});

<span class="hljs-keyword">const</span> array = annotationGroup([annotation, annotation2, annotation3, annotation4]);
array.show();
</code></pre>
<p>This time, we have added quite a bit. But don't let it get overwhelming. We'll walk through it step by step.</p>
<p>First, we have added <code>padding</code> to our <code>annotation2</code> animation. Just like we saw with the header, the <code>roughNotation</code> (which is the <code>rough-notation</code> class in our HTML) gets a yellow circle with a padding of 7.</p>
<p>But padding isn't the only new attribute we introduced. <code>annotation4</code> has a few new things we need to learn about. The object parameter has an attribute, <code>brackets</code>, with an array as value. <code>left</code> and <code>right</code> indicate that we want opening and closing brackets on both sides of the element. It also has <code>strokeWidth</code>, which determines the thickness of the brackets.</p>
<p>Since we have to "show" the animation of each element, which kind of gets boring if we have to animate a lot, I created an array, stored each animation in it, and then "showed" the array all at once. It's neat, and saves a lot of time.</p>
<p>So we've introduced <code>annotationGroup</code>. For this to take effect, we are going to add it to our import line like this:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> { annotate, annotationGroup } <span class="hljs-keyword">from</span> <span class="hljs-string">"https://unpkg.com/rough-notation?module"</span>;
</code></pre>
<p>So... our final site looks like this:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/08/Screenshot-from-2022-08-01-19-46-08.png" alt="Final screenshot with all animations put in place." width="600" height="400" loading="lazy"></p>
<p>The animations will work better on your browser, because you get to refresh and see them take effect one after the other.</p>
<h1 id="heading-conclusion">Conclusion</h1>
<p>Writing this was fun! And I hope that you not only learned something new, but that you tried it out too.</p>
<p>Make sure to check out the Rough Notation repository and docs, because they cover a whole lot more than what we discussed in this article.</p>
<p>Happy animating!</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Build an Animated Landing Page with GSAP and TailwindCSS ]]>
                </title>
                <description>
                    <![CDATA[ By Paul Akinyemi Animations are a crucial part of any great website. Why? When done well, animations vastly improve the user experience of any site, as they help make sites fun and intuitive to use. This article will show you how to build an animated... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-build-an-animated-landing-page-with-gsap-and-tailwindcss/</link>
                <guid isPermaLink="false">66d46090f855545810e934b9</guid>
                
                    <category>
                        <![CDATA[ animation ]]>
                    </category>
                
                    <category>
                        <![CDATA[ JavaScript ]]>
                    </category>
                
                    <category>
                        <![CDATA[ tailwind ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Web Development ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ freeCodeCamp ]]>
                </dc:creator>
                <pubDate>Tue, 12 Apr 2022 23:56:31 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2022/04/gsap-gears.jpg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>By Paul Akinyemi</p>
<p>Animations are a crucial part of any great website. Why? When done well, animations vastly improve the user experience of any site, as they help make sites fun and intuitive to use.</p>
<p>This article will show you how to build an animated landing page with the help of a JavaScript library called <a target="_blank" href="https://greensock.com/docs/v3">GSAP</a>.</p>
<p>GSAP is a magnificent toolkit for building animations. It's been used in roughly <strong>11,000,000</strong> websites so far, has excellent performance, and takes care of browser inconsistencies for you, among other <a target="_blank" href="https://greensock.com/why-gsap">great features</a>.</p>
<p>The landing page you'll be building was inspired by this <a target="_blank" href="https://twitter.com/Ayoolafelix/status/1479157194029514754?s=20">Twitter post</a>. This is what it'll look like when you're done:</p>
<div class="embed-wrapper">
        <iframe width="640" height="360" src="https://player.vimeo.com/video/697946646" style="aspect-ratio: 16 / 9; width: 100%; height: auto;" title="Vimeo embed" allow="autoplay; fullscreen; picture-in-picture" allowfullscreen="" loading="lazy"></iframe></div>
<p>You can check out a live demo <a target="_blank" href="https://gsap-landing-psi.vercel.app/">here</a>.</p>
<h2 id="heading-intended-audience">Intended Audience</h2>
<p>This article assumes that you're a web developer who has a basic grasp of HTML, CSS, and JavaScript, as well as some familiarity with <a target="_blank" href="https://tailwindcss.com/docs/installation">TailwindCSS</a>, NPM, and using the terminal.  </p>
<p>The article also assumes you'll be using a Linux terminal. If you're using Windows instead, check out <a target="_blank" href="https://www.geeksforgeeks.org/linux-vs-windows-commands/">this article</a> to see the Windows cmd equivalent of the terminal commands the article uses.</p>
<p>Knowing GSAP is not a prerequisite, as this article provides an introduction to the features of the library used in the tutorial. Just keep in mind that this isn't intended to be a complete guide to the library.</p>
<h2 id="heading-article-overview">Article Overview</h2>
<p>This article consists of the following sections:</p>
<ul>
<li>How to set up the project</li>
<li>Writing the markup</li>
<li>A brief introduction to GSAP</li>
<li>Adding animation to the page</li>
<li>Conclusion</li>
</ul>
<h2 id="heading-how-to-set-up-the-project">How to Set Up the Project</h2>
<p>Before you start building the landing page, there are a few things you need to put in place.</p>
<p>In this section, you're going to:</p>
<ul>
<li>Set up the directory your project will live in.</li>
<li>Set up GSAP and TailwindCSS.</li>
<li>Import a font.</li>
<li>Set up a simple development server.</li>
</ul>
<h3 id="heading-how-to-set-up-the-project-directory">How to set up the project directory</h3>
<p>Start by running the following commands in your terminal:</p>
<pre><code class="lang-sh">mkdir gsap-landing
<span class="hljs-built_in">cd</span> gsap-landing
mkdir build src
mkdir build/assets build/static
</code></pre>
<p>That code should create a tree of folders that looks like this:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/04/gsap-landing-structure.png" alt="Image" width="600" height="400" loading="lazy">
<em>directory structure for the project</em></p>
<h3 id="heading-how-to-set-up-gsap">How to set up GSAP</h3>
<p>To install GSAP, create a file in build called <code>index.html</code>, then put the following code into it:</p>
<pre><code class="lang-html"><span class="hljs-meta">&lt;!DOCTYPE <span class="hljs-meta-keyword">html</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">html</span> <span class="hljs-attr">lang</span>=<span class="hljs-string">"en"</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">head</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">charset</span>=<span class="hljs-string">"UTF-8"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">http-equiv</span>=<span class="hljs-string">"X-UA-Compatible"</span> <span class="hljs-attr">content</span>=<span class="hljs-string">"IE=edge"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"viewport"</span> <span class="hljs-attr">content</span>=<span class="hljs-string">"width=device-width, initial-scale=1.0"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">script</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"https://cdnjs.cloudflare.com/ajax/libs/gsap/3.10.2/gsap.min.js"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">title</span>&gt;</span>Orfice<span class="hljs-tag">&lt;/<span class="hljs-name">title</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">head</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">body</span>&gt;</span>

<span class="hljs-tag">&lt;/<span class="hljs-name">body</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">html</span>&gt;</span>
</code></pre>
<p>This creates a basic HTML document, and imports GSAP through the script tag in the head.</p>
<h3 id="heading-how-to-set-up-tailwindcss">How to set up TailwindCSS</h3>
<p>To install TailwindCSS, make sure you're in the root directory for your project, then run the following commands in your terminal:</p>
<pre><code class="lang-sh">npm install tailwindcss
npx tailwind init
</code></pre>
<p>This should create three new files in your project root: <code>package.json</code>, <code>package-lock.json</code>, and <code>tailwind.config.js</code>.</p>
<p>Next, create a file in the <code>src</code> folder called <code>input.css</code>, and put the following code into it:</p>
<pre><code class="lang-css"><span class="hljs-keyword">@tailwind</span> base;
<span class="hljs-keyword">@tailwind</span> components;
<span class="hljs-keyword">@tailwind</span> utilities;
</code></pre>
<p>Go back to the project root, and replace the contents of <code>tailwind.config.js</code> with the following:</p>
<pre><code class="lang-js"><span class="hljs-built_in">module</span>.exports = {
  <span class="hljs-attr">content</span>: [
  <span class="hljs-string">"./build/**/*.{html,js}"</span>
  ],
  <span class="hljs-attr">theme</span>: {
    <span class="hljs-attr">extend</span>: {},
  },
  <span class="hljs-attr">plugins</span>: [],
}
</code></pre>
<p>After that, open your <code>package.json</code> file and replace its contents with the following:</p>
<pre><code class="lang-json">{
  <span class="hljs-attr">"scripts"</span>: {
    <span class="hljs-attr">"build-css"</span>: <span class="hljs-string">"npx tailwindcss -i ./src/input.css -o ./build/static/output.css --watch"</span>
  },
  <span class="hljs-attr">"dependencies"</span>: {
    <span class="hljs-attr">"tailwindcss"</span>: <span class="hljs-string">"^3.0.23"</span>
  }
}
</code></pre>
<p>Now, open up your terminal and run this command:</p>
<pre><code class="lang-sh">npm run build-css
</code></pre>
<p>This command is responsible for creating and updating the file: <code>build/static/output.css</code>, which is where the styling for your landing page will live, so you should keep it running in its own terminal window until you're done with the tutorial.</p>
<p>Next, link the CSS to your landing page by adding the following code to <code>build/index.html</code>, just above the script tag that imports GSAP:</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">link</span> <span class="hljs-attr">rel</span>=<span class="hljs-string">"stylesheet"</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"static/output.css"</span>&gt;</span>
</code></pre>
<p> That concludes the setup for TailwindCSS.</p>
<h3 id="heading-how-to-import-the-font">How to import the font</h3>
<p>Replace the head of <code>build/index.html</code> with the following:</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">head</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">charset</span>=<span class="hljs-string">"UTF-8"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">http-equiv</span>=<span class="hljs-string">"X-UA-Compatible"</span> <span class="hljs-attr">content</span>=<span class="hljs-string">"IE=edge"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"viewport"</span> <span class="hljs-attr">content</span>=<span class="hljs-string">"width=device-width, initial-scale=1.0"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">link</span> <span class="hljs-attr">rel</span>=<span class="hljs-string">"preconnect"</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"https://fonts.googleapis.com"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">link</span> <span class="hljs-attr">rel</span>=<span class="hljs-string">"preconnect"</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"https://fonts.gstatic.com"</span> <span class="hljs-attr">crossorigin</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">link</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"https://fonts.googleapis.com/css2?family=Be+Vietnam+Pro:wght@400;500;600;700&amp;display=swap"</span> <span class="hljs-attr">rel</span>=<span class="hljs-string">"stylesheet"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">link</span> <span class="hljs-attr">rel</span>=<span class="hljs-string">"stylesheet"</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"static/output.css"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">script</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"https://cdnjs.cloudflare.com/ajax/libs/gsap/3.10.2/gsap.min.js"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">title</span>&gt;</span>Orfice<span class="hljs-tag">&lt;/<span class="hljs-name">title</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">head</span>&gt;</span>
</code></pre>
<p>Now, apply the font to your CSS. </p>
<p>Open <code>src/input.css</code>, and add the following code to the end of it:</p>
<pre><code class="lang-css">
<span class="hljs-keyword">@layer</span> base {
    <span class="hljs-selector-tag">body</span> {
        @apply overflow-hidden h-screen;
        <span class="hljs-attribute">font-family</span>: <span class="hljs-string">'Be Vietnam Pro'</span>, sans-serif;
    }
}
</code></pre>
<h3 id="heading-how-to-set-up-the-server">How to set up the server</h3>
<p>To setup your development server, open a new terminal window, navigate to your project root, then run the following code:</p>
<pre><code class="lang-sh">npm install --save-dev live-server
</code></pre>
<p>That's all you need to do! To start your server, run the following command in your terminal:</p>
<pre><code class="lang-sh">live-server build
</code></pre>
<p>As long as the <code>live-server</code> command is running, it will serve <code>build/index.html</code> at <a target="_blank">localhost:8080</a>, and automatically refresh the page when you make changes to the project.</p>
<h2 id="heading-how-to-write-the-markup">How to Write the Markup</h2>
<p>Take a look at what your page should look like at the end of the animation:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/04/gsap-landing-structure-outline-1.jpg" alt="Image" width="600" height="400" loading="lazy">
<em>structural outline of landing page</em></p>
<p>Let's call the blue section the navbar, the yellow section the header, and the image the preloader.</p>
<p>Your next step is to build each of these sections in the order they appear on the page.</p>
<h3 id="heading-how-to-build-the-navbar">How to build the Navbar</h3>
<p>You're going to need an image in your navbar, so go to <a target="_blank" href="https://raw.githubusercontent.com/Morgenstern2573/gsap-landing/master/build/assets/logo.jpg">this link</a> and download it. Save it in <code>build/assets</code>, with the name <code>logo.jpg</code>.</p>
<p>Your navbar will be split into three sections:</p>
<ul>
<li>the logo on the left</li>
<li>a <code>div</code> in the middle </li>
<li>a button on the right</li>
</ul>
<p>Open <code>build/index.html</code>, and add the following code to the top of the body tag: </p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">nav</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">img</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"assets/logo.jpg"</span> <span class="hljs-attr">alt</span>=<span class="hljs-string">"logo"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"nav-links"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">a</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"#"</span>&gt;</span>Home<span class="hljs-tag">&lt;/<span class="hljs-name">a</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">a</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"#"</span>&gt;</span>Shop<span class="hljs-tag">&lt;/<span class="hljs-name">a</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">a</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"#"</span>&gt;</span>Contact<span class="hljs-tag">&lt;/<span class="hljs-name">a</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">a</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"#"</span>&gt;</span>Testimonials<span class="hljs-tag">&lt;/<span class="hljs-name">a</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"cta"</span>&gt;</span>Let's work together<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">nav</span>&gt;</span>
</code></pre>
<p>Next, you'll add spacing and alignment to your navbar with some CSS.</p>
<p>Open <code>src/input.css</code>, and add the following at the end of the <code>@layer base</code> section:</p>
<pre><code class="lang-css"><span class="hljs-selector-tag">nav</span> {
        @apply flex p-4 <span class="hljs-attribute">md</span>:py-<span class="hljs-number">8</span> md:px-<span class="hljs-number">4</span> lg:p-<span class="hljs-number">12</span>;
        @apply justify-center items-center gap-4;
    }
</code></pre>
<p>Then add this to the end of the file, <em>outside</em> <code>@layer base</code>:</p>
<pre><code class="lang-css"><span class="hljs-keyword">@layer</span> components {
    <span class="hljs-selector-tag">nav</span> &gt; <span class="hljs-selector-tag">img</span> {
        <span class="hljs-attribute">width</span>: <span class="hljs-number">120px</span>;
    }

    <span class="hljs-selector-tag">nav</span> <span class="hljs-selector-tag">a</span> {
        @apply underline;
    }

    <span class="hljs-selector-class">.cta</span> {
        @apply rounded bg-black text-white py-2 px-4;
    }

    <span class="hljs-selector-tag">nav</span> <span class="hljs-selector-class">.cta</span> {
        @apply hidden <span class="hljs-attribute">md</span>:inline-block;
    }

    <span class="hljs-selector-class">.nav-links</span> {
        @apply hidden <span class="hljs-attribute">md</span>:flex gap-<span class="hljs-number">4</span> lg:gap-<span class="hljs-number">8</span> lg:mx-<span class="hljs-number">16</span> xl:mx-<span class="hljs-number">20</span>;
    }
}
</code></pre>
<p>After you've done that, your page should look like this:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/04/image-14.png" alt="Image" width="600" height="400" loading="lazy">
<em>navbar screenshot</em></p>
<p>Now that you've built the navbar, hide it for now so you can animate it into visibility later. </p>
<p>Go back to <code>index.html</code>, and add a class of <code>opacity-0</code> to the <code>nav</code>:</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">body</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">nav</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"opacity-0"</span>&gt;</span>
        <span class="hljs-comment">&lt;!-- leave the rest of the code as it is --&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">nav</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">body</span>&gt;</span>
</code></pre>
<h3 id="heading-how-to-build-the-header">How to build the header</h3>
<p>You're going to implement the header by building three rows.</p>
<p>The first row is made up of some bold, enlarged text, and a paragraph of normal text that you're going to hide when the screen is smaller than 768px (on mobile devices).</p>
<p>The second row is similar to the first one: some bold, enlarged text, shifted to the right, and a rotating SVG in place of the paragraph. The SVG will also be hidden on mobile devices.</p>
<p>The third row will only be visible on mobile devices, and contains a paragraph of text and a button.</p>
<p>Put the following code in <code>build/index.html</code>, after the nav tag:</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">header</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"row first-row"</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">p</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"bold-text"</span>&gt;</span>
                The Possibilities
            <span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>

            <span class="hljs-tag">&lt;<span class="hljs-name">p</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"copy"</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">span</span>&gt;</span>
                    We believe that workspaces
                <span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">span</span>&gt;</span>
                    should be friendly and convenient.
                <span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">span</span>&gt;</span>
                    Here is an invitation into our how
                <span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">span</span>&gt;</span>
                    we design workspaces at curved.
                <span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
            <span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>

        <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"row second-row"</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">p</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"bold-text"</span>&gt;</span>
                Of Workspaces
            <span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>

            <span class="hljs-tag">&lt;<span class="hljs-name">p</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"round-text"</span> &gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">svg</span> <span class="hljs-attr">xmlns</span>=<span class="hljs-string">"http://www.w3.org/2000/svg"</span> <span class="hljs-attr">width</span>=<span class="hljs-string">"106"</span> <span class="hljs-attr">height</span>=<span class="hljs-string">"106"</span> <span class="hljs-attr">viewBox</span>=<span class="hljs-string">"0 0 106 106"</span> <span class="hljs-attr">fill</span>=<span class="hljs-string">"none"</span>&gt;</span>
                    <span class="hljs-tag">&lt;<span class="hljs-name">path</span> <span class="hljs-attr">d</span>=<span class="hljs-string">"M0,53a53,53 0 1,0 106,0a53,53 0 1,0 -106,0"</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"curve"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">path</span>&gt;</span>
                    <span class="hljs-tag">&lt;<span class="hljs-name">text</span> <span class="hljs-attr">width</span>=<span class="hljs-string">"314.1593"</span>&gt;</span>
                            <span class="hljs-tag">&lt;<span class="hljs-name">textPath</span> <span class="hljs-attr">alignment-baseline</span>=<span class="hljs-string">"top"</span> <span class="hljs-attr">xlink:href</span>=<span class="hljs-string">"#curve"</span>&gt;</span>
                                    office workspace . office workspace . office workspace .
                            <span class="hljs-tag">&lt;/<span class="hljs-name">textPath</span>&gt;</span>
                    <span class="hljs-tag">&lt;/<span class="hljs-name">text</span>&gt;</span>
                    <span class="hljs-tag">&lt;<span class="hljs-name">defs</span>&gt;</span>
                    <span class="hljs-tag">&lt;/<span class="hljs-name">defs</span>&gt;</span>
                <span class="hljs-tag">&lt;/<span class="hljs-name">svg</span>&gt;</span>
            <span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>

        <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"row mobile-row"</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">p</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"copy"</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">span</span>&gt;</span>
                    We believe that workspaces
                <span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">span</span>&gt;</span>
                    should be friendly and convenient.
                <span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">span</span>&gt;</span>
                    Here is an invitation into our how
                <span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">span</span>&gt;</span>
                    we design workspaces at curved.
                <span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
            <span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>

            <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"cta"</span>&gt;</span>Let's work together<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">header</span>&gt;</span>
</code></pre>
<p>Now that the structure is in place, time for the visual effects.</p>
<p>You're going to define a custom utility class called <code>animate-spin-slow</code>, which applies a slow rotating animation to the element it's used on.</p>
<p>Replace the contents of <code>tailwind.config.js</code> with the following:</p>
<pre><code class="lang-js"><span class="hljs-built_in">module</span>.exports = {
  <span class="hljs-attr">content</span>: [
    <span class="hljs-string">"./build/**/*.{html,js}"</span>
  ],
  <span class="hljs-attr">theme</span>: {
    <span class="hljs-attr">extend</span>: {
      <span class="hljs-attr">animation</span>: {
        <span class="hljs-string">'spin-slow'</span>: <span class="hljs-string">'spin 10s linear infinite'</span>,
      }
    },
  },
  <span class="hljs-attr">plugins</span>: [],
}
</code></pre>
<p>Next, you're going to write the styling for the header itself.</p>
<p>Put the following code in <code>src/input.css</code>, inside <code>@layer components</code>:</p>
<pre><code class="lang-css">    <span class="hljs-selector-class">.row</span> {
        @apply flex p-4 justify-center <span class="hljs-attribute">md</span>:justify-start;
        @apply items-center gap-4 <span class="hljs-attribute">md</span>:gap-<span class="hljs-number">8</span>;
        @apply <span class="hljs-attribute">lg</span>:gap-<span class="hljs-number">12</span> text-center md:text-left;
    }

    <span class="hljs-selector-class">.first-row</span> {
        @apply <span class="hljs-attribute">md</span>:pt-<span class="hljs-number">8</span> lg:pt-<span class="hljs-number">16</span>;
    }

    <span class="hljs-selector-class">.bold-text</span> {
        @apply font-bold text-5xl <span class="hljs-attribute">lg</span>:text-<span class="hljs-number">6</span>xl xl:text-<span class="hljs-number">8</span>xl;
    }

    <span class="hljs-selector-class">.copy</span> {
        @apply font-medium;
    }

    <span class="hljs-selector-class">.second-row</span> <span class="hljs-selector-class">.bold-text</span> {
        @apply <span class="hljs-attribute">lg</span>:pl-<span class="hljs-number">16</span> xl:pl-<span class="hljs-number">36</span>
    }

    <span class="hljs-selector-class">.first-row</span> <span class="hljs-selector-class">.copy</span> {
        @apply hidden <span class="hljs-attribute">md</span>:flex md:flex-col;
    }

    <span class="hljs-selector-class">.round-text</span> {
        @apply hidden <span class="hljs-attribute">md</span>:block pl-<span class="hljs-number">20</span> lg:pl-<span class="hljs-number">40</span>;
    }

    <span class="hljs-selector-class">.round-text</span> <span class="hljs-selector-tag">svg</span>{
        @apply animate-spin-slow;
    }

    <span class="hljs-selector-class">.round-text</span> <span class="hljs-selector-tag">textPath</span> {
        @apply text-xs fill-black;
    }

    <span class="hljs-selector-class">.mobile-row</span> {
        @apply flex <span class="hljs-attribute">md</span>:hidden flex-col py-<span class="hljs-number">4</span>;
    }
</code></pre>
<p>At this point, your page should look like this:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/04/image-16.png" alt="Image" width="600" height="400" loading="lazy">
<em>header screenshot</em></p>
<p>Your navbar should be present on the page, but invisible, which is the cause of the white space at the top.</p>
<p>Now, hide all the blocks in each row, by giving them a class of <code>opacity-0</code>. Edit <code>index.html</code> to look like this:</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">header</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"row first-row"</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">p</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"bold-text opacity-0"</span>&gt;</span>
                    <span class="hljs-comment">&lt;!-- leave as is --&gt;</span>
                <span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>

                <span class="hljs-tag">&lt;<span class="hljs-name">p</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"copy opacity-0"</span>&gt;</span>
                    <span class="hljs-comment">&lt;!-- leave as is --&gt;</span>
                <span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>

        <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"row second-row"</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">p</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"bold-text opacity-0"</span>&gt;</span>
                <span class="hljs-comment">&lt;!-- leave as is --&gt;</span>
            <span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>

            <span class="hljs-tag">&lt;<span class="hljs-name">p</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"round-text opacity-0"</span> &gt;</span>
                <span class="hljs-comment">&lt;!-- leave as is --&gt;</span>
            <span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>

        <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"row mobile-row"</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">p</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"copy opacity-0"</span>&gt;</span>
                <span class="hljs-comment">&lt;!-- leave as is --&gt;</span>
            <span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>

            <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"cta opacity-0"</span>&gt;</span><span class="hljs-comment">&lt;!-- leave as is --&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">header</span>&gt;</span>
</code></pre>
<p>And you're done with the header!</p>
<h3 id="heading-how-to-build-the-preloader">How to build the Preloader</h3>
<p>First, download the image from <a target="_blank" href="https://raw.githubusercontent.com/Morgenstern2573/gsap-landing/master/build/assets/office.jpg">this link</a>. Save it in <code>build/assets</code> as <code>office.jpg</code>.</p>
<p>Now that you have the image, you're going to write the actual markup. </p>
<p>The preloader is going to consist of a div with the image inside, and an inner div to serve as an overlay.  </p>
<p>Put the following code in <code>index.html</code>, outside the header tag:</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"pre-loader"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">img</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"assets/office.jpg"</span> <span class="hljs-attr">alt</span>=<span class="hljs-string">"an office"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"overlay"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
</code></pre>
<p>Now, you're going to position the preloader in the middle of the page, and add styling to the overlay.</p>
<p>Put the following code in <code>src/input.css</code>, inside <code>@layer components</code>:</p>
<pre><code class="lang-css"><span class="hljs-selector-class">.pre-loader</span> {
        @apply absolute z-10;
        <span class="hljs-attribute">width</span>: <span class="hljs-number">40vw</span>;
        <span class="hljs-attribute">top</span>: <span class="hljs-built_in">calc</span>(<span class="hljs-number">50%</span> - (<span class="hljs-number">0.668</span> * <span class="hljs-number">20vw</span>));
        <span class="hljs-attribute">left</span>: <span class="hljs-built_in">calc</span>(<span class="hljs-number">50%</span> - <span class="hljs-number">20vw</span>);
    }

    <span class="hljs-selector-class">.pre-loader</span> &gt; <span class="hljs-selector-class">.overlay</span> {
        @apply absolute inset-x-0 bottom-0;
        @apply top-full bg-black bg-opacity-10 -z-0;
    }
</code></pre>
<p>After that, your webpage should look like this:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/04/image-15.png" alt="Image" width="600" height="400" loading="lazy">
<em>preloader screenshot</em></p>
<h2 id="heading-a-brief-introduction-to-gsap">A Brief Introduction to GSAP</h2>
<p>In this section, we're going to quickly go over a few of GSAP's features. Feel free to skip this if you already have some experience with GSAP.</p>
<p>According to the GSAP docs:</p>
<blockquote>
<p>GSAP is a property manipulator  </p>
<p>Animation ultimately boils down to changing property values many times per second, making something appear to move, fade, spin, etc. GSAP snags a starting value, an ending value and then interpolates between them 60 times per second.  </p>
<p>For example, changing the <code>x</code> coordinate of an object from 0 to 1000 over the course of 1 second makes it move quickly to the right. Gradually changing <code>opacity</code> from 1 to 0 makes an element fade out. Your job as an animator is to decide which properties to change, how quickly, and the motion's style. (Source: <a target="_blank" href="https://greensock.com/get-started/#what-is-gsap">What is GSAP</a>?)</p>
</blockquote>
<p>To paraphrase: at its core, GSAP is a library that allows you to smoothly change any property of an object between two set points over some time.</p>
<p>GSAP has a lot of features, but we'll focus on the ones you'll need to build your landing page. You'll be using:</p>
<ul>
<li><code>gsap.to()</code></li>
<li><code>gsap.set()</code></li>
<li><code>gsap.fromTo()</code></li>
<li>Timelines</li>
</ul>
<h3 id="heading-gsapto-method">gsap.to() method</h3>
<p>This method tells GSAP to animate a target from its current state to a specified end state.</p>
<p>The method takes two arguments:</p>
<ul>
<li>The animation target. It can either be a raw object, an array of objects, or a string that contains a CSS query selector (to target a DOM element).</li>
<li>An object which lists out: which properties you're animating, their final values, and special properties that affect the animation itself (like setting the duration or a delay).</li>
</ul>
<p>Here's an example: </p>
<pre><code class="lang-js">gsap.to(<span class="hljs-string">'#object'</span>, {<span class="hljs-attr">top</span>: <span class="hljs-string">'75%'</span>, <span class="hljs-attr">duration</span>: <span class="hljs-number">2</span>})
</code></pre>
<p>That code tells GSAP to change the top property of the DOM element with an id of object to a value of 75%, and to make the change last two seconds.</p>
<h3 id="heading-gsapset-method">gsap.set() method</h3>
<p>This method works almost exactly the same as <code>gsap.to()</code>. It also animates the target to a given end state. </p>
<p>The difference is that <code>gsap.set()</code> creates an animation with a duration of zero seconds, instantly setting the properties of the target to their given values.</p>
<p>Here's an example:</p>
<pre><code class="lang-js">gsap.set(<span class="hljs-string">'#object'</span>, {<span class="hljs-attr">top</span>: <span class="hljs-string">'75%'</span>})
</code></pre>
<p>Once this code runs, the top property of <code>#object</code> becomes 75%.</p>
<h3 id="heading-gsapfromto-method">gsap.fromTo() method</h3>
<p>The <code>fromTo()</code> method tells GSAP to animate the target object from a starting state we provide to an ending state we also provide. When the method executes, the target will be instantly set to the starting state, and then animated to the ending state.</p>
<p>The <code>fromTo()</code> method accepts three arguments:</p>
<ul>
<li>The target argument.</li>
<li>An object which contains the properties you want the target to have at the beginning of the animation.</li>
<li>An object which contains the properties you want the target to have at the end of the animation.</li>
</ul>
<p>All special properties that control the animation itself can only go in the last argument, the object that contains the end state.</p>
<p>Here's an example:</p>
<pre><code class="lang-js">gsap.fromTo(<span class="hljs-string">'#object'</span>, {<span class="hljs-attr">top</span>: <span class="hljs-string">'75%'</span>}, {<span class="hljs-attr">top</span>: <span class="hljs-string">'33%'</span>, <span class="hljs-attr">delay</span>: <span class="hljs-number">3</span>})
</code></pre>
<h3 id="heading-timelines">Timelines</h3>
<p>A GSAP timeline is a special object that acts as a container for multiple animations. Its job is to make sequencing related animations much easier.</p>
<p>This is how timelines work: you create a timeline with <code>gsap.timeline()</code>, and then add animations to it with the same methods we've discussed so far. </p>
<p>Timelines also allow you to specify default special properties for each animation in the timeline, by passing them to <code>gsap.timeline()</code> as properties of an object.</p>
<p>Example:</p>
<pre><code class="lang-js"><span class="hljs-keyword">let</span> timeLine = gsap.timeline({<span class="hljs-attr">defaults</span>: {<span class="hljs-attr">duration</span>: <span class="hljs-number">1</span>}})

timeLine.set(<span class="hljs-string">'#object'</span>, {<span class="hljs-attr">top</span>: <span class="hljs-string">'75%'</span>})
timeLine.to(<span class="hljs-string">'#object'</span>, {<span class="hljs-attr">top</span>: <span class="hljs-string">'50%'</span>, <span class="hljs-attr">delay</span>: <span class="hljs-number">0.5</span>})
timeLine.fromTo(<span class="hljs-string">'#object'</span>, {<span class="hljs-attr">top</span>: <span class="hljs-string">'60%'</span>}, {<span class="hljs-attr">top</span>: <span class="hljs-string">'25%'</span>, <span class="hljs-attr">delay</span>: <span class="hljs-number">0.5</span>})
</code></pre>
<p>That's everything you need to know about GSAP to understand the rest of this tutorial.</p>
<h2 id="heading-how-to-add-animation">How to Add Animation</h2>
<p>Now that all the markup is in place, it's finally time to add the animation.</p>
<p>Start by creating a new file in <code>build/static</code> called <code>script.js</code>.  </p>
<p>This is what will contain all your animation JavaScript. Next, link <code>script.js</code> to your HTML by adding a script tag to <code>index.html</code> just above the closing body tag, like this:</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">body</span>&gt;</span>
    <span class="hljs-comment">&lt;!-- leave as is --&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">script</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"static/script.js"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">body</span>&gt;</span>
</code></pre>
<p>The first thing you're going to animate is your preloader. You're going to write code to slowly increase the height of the overlay, and then to increase its width while moving it down and to the left.</p>
<p>Add the following to <code>static/script.js</code>:</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> timeLine = gsap.timeline({<span class="hljs-attr">defaults</span>: {<span class="hljs-attr">duration</span>: <span class="hljs-number">1</span>}})

timeLine.to(<span class="hljs-string">'.pre-loader &gt; .overlay'</span>, {<span class="hljs-attr">top</span>: <span class="hljs-string">'75%'</span>})
timeLine.to(<span class="hljs-string">'.pre-loader &gt; .overlay'</span>, {<span class="hljs-attr">top</span>: <span class="hljs-string">'50%'</span>, <span class="hljs-attr">delay</span>: <span class="hljs-number">0.5</span>})
timeLine.to(<span class="hljs-string">'.pre-loader &gt; .overlay'</span>, {<span class="hljs-attr">top</span>: <span class="hljs-string">'25%'</span>, <span class="hljs-attr">delay</span>: <span class="hljs-number">0.5</span>})
timeLine.to(<span class="hljs-string">'.pre-loader &gt; .overlay'</span>, {<span class="hljs-attr">top</span>: <span class="hljs-string">'0'</span>, <span class="hljs-attr">delay</span>: <span class="hljs-number">0.5</span>})
timeLine.to(<span class="hljs-string">'.pre-loader'</span>, {<span class="hljs-attr">width</span>: <span class="hljs-string">'80vw'</span>, <span class="hljs-attr">left</span>:<span class="hljs-number">0</span>, <span class="hljs-attr">top</span>: <span class="hljs-string">'50%'</span>})
timeLine.set(<span class="hljs-string">'.pre-loader'</span>, {<span class="hljs-string">'z-index'</span>: <span class="hljs-number">-20</span>})
</code></pre>
<p>Let's take a second to break this code down. It does a few things:</p>
<ul>
<li>It creates a timeline for our animations, setting a default duration of 1 second.</li>
<li>It uses <code>gsap.to()</code> to increase the height of the overlay by adjusting the <code>top</code> property.</li>
<li>It uses <code>gsap.to()</code> to increase the width of the preloader, align it with the left edge of the screen, and increase the width.</li>
<li>It uses <code>gsap.set()</code> to immediately set the <code>z-index</code> to -20, so it won't cover any of our text.</li>
</ul>
<p>Next up is the navbar. You want to create an effect where it looks like the navbar is sliding in from above the screen, and gradually becoming visible at the same time.</p>
<p>Do that by adding the following code to the end of <code>script.js</code>:</p>
<pre><code class="lang-js">timeLine.fromTo(<span class="hljs-string">'nav'</span>, {<span class="hljs-attr">y</span>:<span class="hljs-number">-100</span>}, {<span class="hljs-attr">y</span>:<span class="hljs-number">0</span>, <span class="hljs-attr">opacity</span>:<span class="hljs-number">1</span>})
</code></pre>
<p>That code uses <code>gsap.fromTo()</code> to set a <code>transalateY(-100px)</code>on the element, and then animate it to its normal position and full opacity.</p>
<p>You're going to animate the header now, piece by piece. </p>
<p>The first thing to do is to animate the bold text in the first row. You're going to implement the exact same kind of animation on it, but it's going to slide in from the bottom, not the top.</p>
<p>Add this to the end of <code>script.js</code>:</p>
<pre><code class="lang-js">timeLine.fromTo(<span class="hljs-string">'.first-row .bold-text'</span>, {<span class="hljs-attr">y</span>:<span class="hljs-number">100</span>}, {<span class="hljs-attr">y</span>:<span class="hljs-number">0</span>, <span class="hljs-attr">opacity</span>:<span class="hljs-number">1</span>}, <span class="hljs-string">"&lt;"</span>)
</code></pre>
<p>The last argument, <code>&lt;</code>, tells GSAP to start this animation at the same time as the previous animation in the timeline. Since both animations have the same duration, this has the effect of executing them simultaneously.</p>
<p>Next, animate the bold text in the second row in the same way, but leave out the <code>&lt;</code> argument, like this:</p>
<pre><code class="lang-js">timeLine.fromTo(<span class="hljs-string">'.second-row .bold-text'</span>, {<span class="hljs-attr">y</span>:<span class="hljs-number">100</span>}, {<span class="hljs-attr">y</span>:<span class="hljs-number">0</span>, <span class="hljs-attr">opacity</span>:<span class="hljs-number">1</span>, <span class="hljs-attr">delay</span>:<span class="hljs-number">0.5</span>})
</code></pre>
<p>The remaining parts of the header are interesting, because which elements you want to animate next depend on whether the site is viewed on a mobile device or not.</p>
<p>If the site is on mobile, what you want to animate are the elements of the third row. But if it isn't, you animate the remaining bits of the first and second rows.</p>
<p>You're going to solve this by using the <a target="_blank" href="https://developer.mozilla.org/en-US/docs/web/api/window/matchmedia">window.matchMedia() method</a>. </p>
<p>It takes a media query as its argument, and allows you to check whether the browser matches that media query or not.</p>
<p>Add this code at the end of <code>script.js</code>:</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> isMobile = !(<span class="hljs-built_in">window</span>.matchMedia(<span class="hljs-string">'(min-width: 768px)'</span>).matches)

<span class="hljs-keyword">if</span> (isMobile) {
    timeLine.fromTo(<span class="hljs-string">'.mobile-row .copy'</span>, {<span class="hljs-attr">y</span>:<span class="hljs-number">100</span>}, {<span class="hljs-attr">y</span>:<span class="hljs-number">0</span>, <span class="hljs-attr">opacity</span>:<span class="hljs-number">1</span>, <span class="hljs-attr">delay</span>:<span class="hljs-number">0.5</span>})
    timeLine.fromTo(<span class="hljs-string">'.mobile-row .cta'</span>, {<span class="hljs-attr">y</span>:<span class="hljs-number">100</span>}, {<span class="hljs-attr">y</span>:<span class="hljs-number">0</span>, <span class="hljs-attr">opacity</span>:<span class="hljs-number">1</span>, <span class="hljs-attr">delay</span>:<span class="hljs-number">0.5</span>})
} <span class="hljs-keyword">else</span> {
    timeLine.fromTo(<span class="hljs-string">'.first-row .copy'</span>, {<span class="hljs-attr">y</span>:<span class="hljs-number">100</span>}, {<span class="hljs-attr">y</span>:<span class="hljs-number">0</span>, <span class="hljs-attr">opacity</span>:<span class="hljs-number">1</span>, <span class="hljs-attr">delay</span>:<span class="hljs-number">0.5</span>})
    timeLine.set(<span class="hljs-string">'.round-text'</span>, {<span class="hljs-attr">opacity</span>:<span class="hljs-number">1</span>, <span class="hljs-attr">delay</span>:<span class="hljs-number">0.5</span>})
}
</code></pre>
<p>Let's walk through that. The code you just added:</p>
<ul>
<li>Determines whether the width of the viewport is less than 768px.</li>
<li>If it is, the code makes the paragraph in the mobile row slide up, followed by the button.</li>
<li>If it isn't, it makes the paragraph in the first row slide up, and then makes the SVG visible.</li>
</ul>
<p>And that completes your landing page!</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>In this article, you learned how to use the basics of GSAP to build a couple of cool animations. If you would like to learn more about GSAP and the awesome things you can do with it, visit <a target="_blank" href="https://greensock.com/learning">this link</a>. </p>
<p>You can find a the complete codebase <a target="_blank" href="https://github.com/Morgenstern2573/gsap-landing-article">here</a>.</p>
<p>If you enjoyed this article, follow me on <a target="_blank" href="https://twitter.com/apexPaul09">Twitter</a> to know when I write something new!</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Web Animation Performance Fundamentals – How to Make Your Pages Look Smooth ]]>
                </title>
                <description>
                    <![CDATA[ By Reza Lavarian What if I told you that web pages were interactive animations played back by your web browser? We watch various motions every time we're on a web page.  And it's not only JavaScript or CSS animations that I'm talking about. Scrolling... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/web-animation-performance-fundamentals/</link>
                <guid isPermaLink="false">66d460c7868774922c885002</guid>
                
                    <category>
                        <![CDATA[ animation ]]>
                    </category>
                
                    <category>
                        <![CDATA[ CSS ]]>
                    </category>
                
                    <category>
                        <![CDATA[ web performance ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ freeCodeCamp ]]>
                </dc:creator>
                <pubDate>Mon, 28 Feb 2022 18:49:59 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2022/02/Antics_2-D_Animation_infobox_screenshot-1.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>By Reza Lavarian</p>
<p>What if I told you that web pages were interactive animations played back by your web browser?</p>
<p>We watch various motions every time we're on a web page. </p>
<p>And it's not only JavaScript or CSS animations that I'm talking about. Scrolling, pinch zooming, text selection, and even hovering over a button are technically animations and work similarly.</p>
<p>In fact, they are sequential images displayed rapidly to give us a perception of motion or simply reflect a change.</p>
<p>Every time JavaScript code changes the page, an area in the previous image is invalidated, and the browser draws a new one.</p>
<p>These changes could be as simple as adding or removing a <code>&lt;div&gt;</code> element or changing the styles of a button. </p>
<p>We refer to these images as <strong>frames</strong>.</p>
<p><a target="_blank" href="https://www.w3.org/TR/frame-timing/#h-introduction">Based on W3C frame timing guidelines</a>, the web browser has to be able to display sixty frames per second (60 fps).</p>
<p>Of course, a frame stays on the screen if there's no change.</p>
<p>How about I show you some examples?</p>
<p>When you scroll through a page, the browser displays off-screen areas of the document as you scroll down (or up).</p>
<p>The image below shows the sequential frames produced and displayed during a few seconds of scrolling.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/02/animation-scroll-2.png" alt="Image" width="600" height="400" loading="lazy">
<em>Generated frames during a few seconds of scrolling</em></p>
<p>And as you can see, each frame was displayed for 16.7ms (60 fps). </p>
<p>I used <a target="_blank" href="https://developer.chrome.com/docs/devtools/">Google Chrome DevTools</a> to create the above recording. You can reproduce it if you want. While in the DevTools, go to the <strong>Performance</strong> panel, and click on the record button. Then, scroll the page for a few seconds, and stop the recording.</p>
<p>You'll see an overview like the one above.</p>
<p>Even when you select a piece of text, new frames are displayed as you select more letters and lines.</p>
<p>In the recording below, I'm moving the mouse over the timeframe to replay the text selection:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/02/text-select.gif" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Why do I need to know this? you may ask.</p>
<p>When a page doesn't respond swiftly to user interactions or has jerky movements, something must be off.</p>
<p>And it's usually owing to the browser's <strong>main thread</strong> being so busy that it can't deliver frames on time (more on this below).</p>
<p>In this guide, I'll explain how browsers turn code into pixels and how we can work with them to deliver a delightful user experience.</p>
<p>I'll focus on Google Chrome for this writing. However, the high-level concepts are the same across all browsers.</p>
<p>There are many theories to cover here, and I hope don't you mind that.</p>
<p>Michael Jordan said, "Keep the fundamentals down, and the level of everything you do will rise."</p>
<p>Trust me, knowing these theories won't be without a reward! </p>
<p>You'll have a new perspective on how web pages change. And we'll get into lots of actions in the end.</p>
<h2 id="heading-refresh-rate-or-frame-rate">Refresh Rate or Frame Rate?</h2>
<p>The average display device refreshes the screen sixty times per second (60Hz).</p>
<p>To the human eyes, any frequency above 12Hz is perceived as motion. <a target="_blank" href="https://paulbakaus.com/tutorials/performance/the-illusion-of-motion/">This article by Paul Bakaus</a> does a great job of explaining it.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/02/Animhorse.gif" alt="Image" width="600" height="400" loading="lazy">
_<strong>[CC BY-SA 2.5 ](https://en.wikipedia.org/wiki/Frame_rate#/media/File:Animhorse.gif"&gt;Animated Horse</strong> (12 drawings per second) by <a href="https://en.wikipedia.org/wiki/User:Janke"><strong>Janke</strong></a>, Licensed under <strong>&lt;a href="https://creativecommons.org/licenses/by-sa/2.5/)</strong>_</p>
<p>There are screens with higher refresh rates like 120Hz or 144Hz, but 60Hz is the standard for most display devices.</p>
<p>The refresh rate is different from the <strong>frame rate</strong>, though.</p>
<p>Refresh rate is the number of times a display device refreshes an image in one second. The frame rate is an arbitrary number of frames (in a filming system), captured or drawn in a second.</p>
<p>For instance, the standard rate for recording films is <a target="_blank" href="https://www.masterclass.com/articles/how-frame-rates-affect-film-and-video#3-standard-frame-rates-for-film-and-tv">24 fps</a>, even though it's not the maximum refresh rate of a modern TV. </p>
<p>In that case, display devices use an algorithm to repeat specific frames to make the frame rate compatible with their refresh rate. This means you can watch 24 fps film on a 144Hz TV at the original 24 fps.</p>
<p>Why does frame rate even matter for web pages, you may ask?</p>
<p>A user who plays games at 120 fps would notice a slow page scroll on the same computer.</p>
<p>They won't enjoy web animations at any rate under 60 fps, either.</p>
<p>Have you ever come across those websites with plenty of ads and GIFs? I usually leave such pages quickly because I know finding another website would save me some time!</p>
<h2 id="heading-theres-a-deadline-to-produce-each-frame">There's a Deadline to Produce Each Frame</h2>
<p>It takes time for the browser to draw a new frame.</p>
<p>Displaying sixty frames per second means each frame must be screen-ready in 16.7ms (1 sec ÷ 60).</p>
<p>Otherwise, the frame would be <strong>delayed</strong> or <strong>dropped</strong>. This issue is often referred to as <strong>jank</strong> on a web page.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/02/plane-1.gif" alt="Image" width="600" height="400" loading="lazy">
<em>An animation with frame drops and delays</em></p>
<p>So our top priority is clear now: we need to make our pages <a target="_blank" href="http://jankfree.org/">jank free</a> 👆.</p>
<p>But first, we need to know how everything works.</p>
<h2 id="heading-how-a-frame-is-produced">How a Frame is Produced</h2>
<p>The web browser generates a new frame because something changed on the page. And it should reflect that change.</p>
<p>A web page changes when:</p>
<p><strong>The user interacts with the page</strong>. They scroll, pinch zoom, click, select a piece of text, and so on.</p>
<p><strong>A piece of JavaScript code changes the page</strong>. For instance, it adds a <code>&lt;div&gt;</code> element or changes a CSS style.</p>
<p>Each change starts a sequence of tasks, which results in a single frame. </p>
<p>This sequence of tasks is known as <strong>pixel pipeline</strong>, <strong>rendering waterfall</strong>, or <strong>rendering pipeline</strong>.</p>
<p>And this is what it looks like from a high-level perspective:</p>
<ul>
<li><strong>JavaScript Evaluate</strong> – the browser: oh, something changed! I need to generate a new frame.</li>
<li><strong>Style Calculate</strong> – the browser: now I must apply class <code>some-class</code> to to that <code>&lt;div&gt;</code> element).</li>
<li><strong>Layout (reflow)</strong> – the browser: I see some elements have new styles now. I need to calculate how much space they take on the screen and where they should be positioned based on these styles. Also, I need to calculate the geometry of every other element affected by this change!</li>
<li><strong>Paint</strong> – the browser: Now, I should group elements (that have an output) in multiple layers and convert each layer into a bitmap representation in the memory or the video RAM.</li>
<li><strong>Compositing</strong> – the browser: Now, I should combine these bitmaps in the defined order to form the final frame.</li>
</ul>
<p>The same steps are also taken when the web page is rendered for the first time.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/02/pipeline-1.png" alt="Image" width="600" height="400" loading="lazy">
<em>The pixel pipeline</em></p>
<p>Each pipeline activity triggers its following activity. For instance, the layout triggers paint, and it continues until the last step.</p>
<p>We need to be mindful of every activity in the pipeline as each can contribute to low performance.</p>
<p>Let's get to know them a bit better.</p>
<h3 id="heading-evaluate-javascript-when-javascript-code-runs">Evaluate JavaScript – when JavaScript code runs</h3>
<p>You usually change the page from your JavaScript code.</p>
<p>Many of us remove an element like so:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">let</span> myBox = <span class="hljs-built_in">document</span>.querySelector(<span class="hljs-string">'.my-box'</span>)

<span class="hljs-keyword">if</span> (myBox) {
 myBox.remove()
}
</code></pre>
<p>Or hide it this way:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">let</span> myBox = <span class="hljs-built_in">document</span>.querySelector(<span class="hljs-string">'.my-box'</span>)

<span class="hljs-keyword">if</span> (myBox) {
  myBox.style.display = <span class="hljs-string">'none'</span>
}
</code></pre>
<p>Or add a CSS selector to its class list:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">let</span> myBox = <span class="hljs-built_in">document</span>.querySelector(<span class="hljs-string">'.my-box'</span>)

<span class="hljs-keyword">if</span> (myBox) {
  myBox.classList.add(<span class="hljs-string">'my-special-box'</span>)
}
</code></pre>
<p>These changes invalidate a portion of the document and make the browser produce a new frame.</p>
<h3 id="heading-style-which-css-styles-go-with-which-element">Style – which CSS styles go with which element</h3>
<p>Next, the web browser associates the new styles with the respective elements based on the matching selectors.</p>
<p>For instance, if you add the class <code>my-special-box</code> to an element's class list:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">let</span> myBox = <span class="hljs-built_in">document</span>.querySelector(<span class="hljs-string">'.my-box'</span>)

<span class="hljs-keyword">if</span> (myBox) {
  myBox.classList.add(<span class="hljs-string">'my-special-box'</span>)
}
</code></pre>
<p>This step is where the respective styles are computed and applied to your element.</p>
<p>Also, as you probably know, <a target="_blank" href="https://developers.google.com/web/fundamentals/performance/critical-rendering-path/constructing-the-object-model">HTML elements and styles are converted into DOM and CSSOM trees, respectively</a>.</p>
<p>The browser uses these data structures internally. But it exposes them to JavaScript via the <a target="_blank" href="https://www.decodingweb.dev/books/decoding-web-development/front-end-skills-to-get-you-started#web-apis">browser APIs</a> too. That's how we manipulated the document in the previous examples – we used the DOM API.</p>
<p>The web browser <strong>combines</strong> DOM and CSSOM to make a tree of all the visible elements within the <code>&lt;body&gt;</code> tag with their computed CSS styles.</p>
<p>This tree is called the <strong>render tree, rendering tree,</strong> or <strong>frame tree</strong>.</p>
<p>CSS Pseudo-elements, which have <code>content</code>, will be in the render tree, too.</p>
<p>The goal is now to turn the render tree into an image.</p>
<h3 id="heading-layout-to-recalculate-the-geometry-of-elements-after-a-change">Layout – to recalculate the geometry of elements after a change</h3>
<p>An HTML element's geometry can affect siblings and children.</p>
<p>When your code adds (or removes) an element or changes its style, the browser recalculates the <em>new</em> dimension and position of that element.</p>
<p>It also calculates the dimension and position of every sibling/child it may affect.</p>
<p>For instance, if you increase a paragraph's <code>margin-top</code> with JavaScript, it'll push down every following element on the document.</p>
<p>Or if a container's <code>width</code> gets smaller, its children might have to shrink in size too.</p>
<p>That said, a simple change to an element's geometry might force the browser to recalculate the geometry of hundreds of other elements affected (directly or indirectly) by the change.</p>
<p>The browser uses the render tree to recalculate the geometry of every visible element within the viewport.</p>
<p>This process is also known as <strong>reflow</strong>.</p>
<h2 id="heading-paint-when-code-is-converted-into-pixels">Paint – When Code is Converted into Pixels</h2>
<p>At this point, the web browser has all the data structures it needs. The styles are computed, and the layout is ready.</p>
<p>Depending on the rendering engine (Blink, Gecko, and so on), more abstractions and auxiliary data structures are created internally. But since browser internals tend to change pretty frequently, we'll keep our discussion as high level as possible. </p>
<p>The next step is to turn code into pixels. This process is called painting. </p>
<p>At this step, the browser's renderer creates a <a target="_blank" href="https://en.wikipedia.org/wiki/Display_list">display list</a> of drawing commands for every element in the render tree.</p>
<p>These commands look like basic drawing commands: <strong>draw a rectangle</strong>, <strong>draw a circle</strong> or <strong>draw a piece of text at these coordinates</strong>.</p>
<p>Google Chrome uses <a target="_blank" href="https://skia.org/">Skia</a> to do the drawing work. Skia is a 2D graphics library that provides standard APIs across various platforms. </p>
<p>Chrome records these commands in a Skia <code>[SkPicture](https://api.skia.org/classSkPicture.html)</code> object. SkPicture has a <code>playback</code> method, which sends the drawing commands one by one to the specified canvas.</p>
<p>Eventually, the output of display lists would be a set of <strong>bitmaps</strong>.</p>
<p>To make sure we're all on the same page, let's quickly define what a bitmap is.</p>
<p>You might know that a pixel (picture element) is the smallest element of a digital image. Every image is a grid of pixels (a*b), and each pixel has a specific color. These pixels together form the image.</p>
<p>Now, what is a bitmap? </p>
<p>Bitmap (in a graphic context) is a method of storing each pixel's color information as a set of bits.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/02/Twitter-post---59.png" alt="Image" width="600" height="400" loading="lazy">
_<strong>[CC0 1.0](https://en.wikipedia.org/wiki/Raster_graphics#/media/File:Rgb-raster-image.svg"&gt;The smiley face</strong> (remixed), Licensed under <strong>&lt;a href="https://creativecommons.org/publicdomain/zero/1.0/deed.en)</strong>_</p>
<p>In the above image, three pixels are highlighted with their color information (a mix of red, green, and blue). </p>
<p>These values together form the bitmap of the image.</p>
<p>On the other hand, a bitmap is how computers store images in the memory or a storage device.</p>
<p>Turning web page content into bitmaps is known as <strong>paint</strong> or <strong>rasterization</strong>.</p>
<p>Nothing is painted yet, though. This step is more of a paint setup (or pre-paint) than the actual paintwork.</p>
<h3 id="heading-elements-are-painted-on-multiple-layers">Elements are painted on multiple layers</h3>
<p>The actual paintwork is done at the discretion of the compositor later on. But the renderer provides enough hints to the compositor on how the elements should be painted on multiple layers.</p>
<p>Some elements are grouped as one layer and rasterized together (they share the same bitmap). However, some elements are painted on a dedicated layer.</p>
<p>For instance, in the animation below, the elements are painted onto four layers:</p>
<div class="embed-wrapper">
        <iframe width="560" height="315" src="https://www.youtube.com/embed/sSgtcdklEgQ" style="aspect-ratio: 16 / 9; width: 100%; height: auto;" title="YouTube video player" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen="" loading="lazy"></iframe></div>
<p>You can see these layers in the Layers panel. </p>
<p>To enable the Layers panel, while in Chrome DevTools, hold ⌘+<strong>⇧</strong>+P (or Ctrl+<strong>⇧</strong> Shift+P) to activate the Command Palette. Then, type "Show Layers" and run it.</p>
<p>These layers (also known as composite layers) make compositing possible.</p>
<p>These composite layers are then combined in the defined order and form the final image (more on this below).</p>
<p>Composite layers are similar to layers in raster graphics editors such as Photoshop. By managing shapes as layers, the designer can transform a shape without affecting other shapes.</p>
<p>If you wanted to change something on a flattened image, you might have to redesign the whole thing. </p>
<p>Like Photoshop, painting elements onto separate layers enables the web browser to significantly reduce paintwork. </p>
<p>So if an element on a layer is invalidated (it's changed), only the invalidated areas (tiles) of the respective layer need to be repainted.</p>
<p>The renderer considers various factors to make the layering decisions. For instance, if an element's CSS <code>opacity</code> will change at runtime, it'll be rasterized onto a dedicated layer.</p>
<p>You can also promote an element to be painted on a dedicated layer with <code>will-change</code> or <code>translateZ(0)</code> CSS properties.</p>
<p>You should always promote a layer for a reason, though.</p>
<p>Having many layers will incur costs on memory and processing time. This can become problematic on devices with limited capacity.</p>
<h3 id="heading-compositing-when-the-final-frame-is-generated">Compositing: when the final frame is generated</h3>
<p>The compositor receives a display list from the renderer with auxiliary data structures. </p>
<p>Its job (among other things) is to arrange drawing the elements as multiple layers. </p>
<p>Depending on what's on the page (and its styles), the painting can be done by software (software rasterization) or directly on the GPU (hardware rasterization).</p>
<p>Here's how it works on Google Chrome (for other browsers, you should check out their designs docs):</p>
<p>In the case of software rasterization, the graphics commands are executed by a set of raster worker threads, and then the generated bitmaps are shared with the GPU as textures.</p>
<p>However, if hardware rasterization kicks in, Skia generates the bitmaps directly on the GPU by issuing low-level commands to the operating system's graphics API.</p>
<p>Once the layers are ready, the compositor can apply compositor-level transformations (like <code>transform</code> and <code>opacity</code>) on each layer.</p>
<p>And finally, it combines (composites) the layers into one. If hardware acceleration is on, compositing will be done on the GPU too – by issuing low-level commands to the operating system's graphics API.</p>
<p>Remember this part because it plays a big role in optimising the animation performance.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/02/Screenshot-2022-02-16-at-18.01.03-1.png" alt="Image" width="600" height="400" loading="lazy">
<em>Layers after being composited</em></p>
<p>Anytime I think about composite layers, it reminds me of the old cel animation production, where each frame was drawn on a transparent celluloid sheet. </p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/02/cel-animation-frame.jpeg" alt="Image" width="600" height="400" loading="lazy">
<em>[CC BY-NC 2.0](https://www.flickr.com/photos/gogdog/5281815537"&gt;<strong>My GunBuster Animation Cel</strong>, Licensed <strong>&lt;a href="https://creativecommons.org/licenses/by-nc/2.0/)</strong></em></p>
<p>The background was a static drawing, and the animator shifted it to the left by an inch (with a roller) and placed the next cel frame on it.</p>
<p>This technique significantly reduced the drawing work and helped animation studios distribute the design work across multiple teams. </p>
<p>You can watch this video of Disney's <a target="_blank" href="https://www.youtube.com/watch?v=aQkJM13PMKw">animation production of Snow White</a> if you're curious about this old production method.</p>
<p>The compositing in the browsers has a similar purpose: <strong>minimizing the paintwork when something changes.</strong></p>
<p>This is the last step of the pipeline – where a new frame is born.</p>
<h2 id="heading-how-to-optimize-the-pipeline-activities">How to Optimize the Pipeline Activities</h2>
<p>One question still remains, though. How can I avoid jerky page movements and stop annoying my users?</p>
<p>Here are a few things you should do.</p>
<h3 id="heading-know-the-most-expensive-changes">Know the most expensive changes</h3>
<p>Not all changes involve every activity of the pixel pipeline. Some changes require less work and might skip a step or two.</p>
<p>Any change to an element's geometry (when you change the height, width, left, top, bottom, right, padding, margin, and so on) involves the whole pipeline.</p>
<p>This type of change is the most expensive change you can make to a web page.</p>
<p>Sometimes it's necessary, but sometimes it's totally avoidable (I'll tell you how).</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/02/pipeline-full-1.png" alt="Image" width="600" height="400" loading="lazy">
<em>All steps of the pixel pipeline</em></p>
<h3 id="heading-optimize-paintwork">Optimize paintwork</h3>
<p>If you change a div's <code>background-color</code> property, the browser won't have to recalculate its geometry – because you only changed the color.</p>
<p>That means the web browser <strong>skips the layout step</strong> this time and jumps to painting.</p>
<p>The painting is still an expensive task. However, you can optimize it by reducing paint complexity – choosing simpler styles over complicated ones.</p>
<p>For instance, text shadows or gradients are more expensive than a simple background color.</p>
<p>Always ask yourself if you can choose a cheaper set of styles. Sometimes they make no difference in terms of aesthetics.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/02/pipeline-paint.png" alt="Image" width="600" height="400" loading="lazy">
<em>Pixel pipeline without the layout step</em></p>
<h3 id="heading-use-composited-only-transformations"><strong>Use composited-only transformations</strong></h3>
<p>Some changes won't require layout and paint because the compositor can apply them on its own.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/02/pipeline-composite.png" alt="Image" width="600" height="400" loading="lazy">
<em>The pixel pipeline without Layout and Paint</em></p>
<p>Below is the list of changes the browser can do cheaply at compositing time:</p>
<ul>
<li><strong>Re-positioning</strong> with transform: <code>translate(mpx, npx)</code></li>
<li><strong>Rotating</strong> with <code>transform:rotate(xdeg)</code></li>
<li><strong>Scaling</strong> with <code>transform: scale(x)</code></li>
<li><strong>Opacity</strong> with <code>opacity(x)</code></li>
</ul>
<p>These CSS properties seem like all you need when making a change to a page (well, most of it)!</p>
<p>Even better, if hardware acceleration is kept on, the compositor can use the GPU's computing power to apply these transformations. GPUs are created for this type of workload.</p>
<p>So, depending on the change we make to the DOM, the process will be one of these three scenarios.</p>
<ul>
<li>JavaScript → Style → Layout → Paint → Composite</li>
<li>JavaScript → Style → Paint → Composite</li>
<li>JavaScript → Style →  Composite</li>
</ul>
<p><strong>"Performance is the art of avoiding work."</strong></p>
<p>And of course, the last scenario is the cheapest route to choose.</p>
<h3 id="heading-try-to-reduce-the-main-threads-workload">Try to reduce the main thread's workload</h3>
<p>A web browser is basically a <a target="_blank" href="https://www.decodingweb.dev/books/processing-fundamentals/how-a-computer-program-works">computer program</a>, and as a computer program, it'll have one or more processes in the memory while running.</p>
<p>Most browsers have a multi-process architecture, where activities are distributed across multiple threads of different processes (like the Renderer process and the GPU process, the Browser process, and so on).</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/02/Google-chrome-processes.png" alt="Image" width="600" height="400" loading="lazy">
<em>The Renderer and GPU process in Google Chrome</em></p>
<p>In the case of Chrome, JavaScript, Style, Layout, paint setup happen in the main thread of the Renderer process (each tab has a dedicated Renderer).</p>
<p>This is almost everything!</p>
<p>The HTML content your browser fetches initially via an <a target="_blank" href="https://www.decodingweb.dev/books/decoding-web-development/http">HTTP request</a> is parsed on a dedicated thread, but rendering and whatever content you add is parsed on the main thread.</p>
<p>That said, the focus should be on taking some load off the shoulders of the main thread. And in return, it helps us have a consistent frame rate.</p>
<p>The <a target="_blank" href="https://csstriggers.com/">CSS Triggers</a> website can help you understand how changing a CSS property triggers layout, paint, and compositing.</p>
<p>You can also use this cheat sheet I created:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/02/Twitter-post---55.png" alt="Image" width="600" height="400" loading="lazy">
<em>CSS properties and their initial step in the pixel pipeline</em></p>
<h3 id="heading-make-sure-your-javascript-callbacks-catch-the-train">Make sure your JavaScript callbacks catch the train!</h3>
<p>Ok, now we know how to help the browser take fewer steps (when possible!), but there's another thing to consider.</p>
<p>Whether it's an animation or a one-off change, we need to make sure our changes are synced with the frame rate at which the browser is displaying the content.</p>
<p>What does it even mean? You may ask.</p>
<p>Imagine a moving train with many wagons. </p>
<p>This train is moving fast, and you have 16.7ms to draw a picture and throw it into each wagon (while it's moving).</p>
<p>If you fail to load a wagon in 16.7ms, it'll briefly stop until you throw the picture.</p>
<p><div class="embed-wrapper"><iframe src="https://giphy.com/embed/TlK63EDww4g4tXUd0gE" width="480" height="320" class="giphy-embed" title="Embedded content" loading="lazy"></iframe></div></p><p><a href="https://giphy.com/gifs/train-subway-station-TlK63EDww4g4tXUd0gE">via GIPHY</a></p><p></p>
<p>That moving train can be any movement on the web page. It could be an animation, transition, a page scroll, text selection, or any other motion.</p>
<p>If the train has to stop for you, it will deliver the frames with a delay. Users will notice it, and they won't like it!</p>
<p>Anytime you want to change the page, you need to somehow slide your work in a 16.7ms slot without slowing it down.</p>
<p>Sometimes it's tricky to do it, though.</p>
<p>Many developers still use <code>setInterval()</code> to make a timed loop. For instance, to repeat an action or create an animation.</p>
<p>There's a problem with  <code>setInterval()</code>, though. It doesn't have enough precision to run your code at the exact frequency you define. </p>
<p>If you set the interval to repeat your code every 16.7ms, your code could run at any point during each 16.7ms slot.</p>
<p>So if we have 16.7ms to make a change, generate the frame, and load it onto its dedicated wagon, we need to make sure our code executes right at the beginning of each 16.7ms slot. </p>
<p>Otherwise, it would require more than 16.7ms to complete, and it won't be ready for the current slot.</p>
<p>What if there was a way to run the callback right at the beginning of each 16.7ms time slot?</p>
<p><code>RequestAnimationFrame()</code> has been designed just for that.</p>
<p>It makes sure your callbacks are executed right at the beginning of the next frame.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/02/requestanimationframe.png" alt="Image" width="600" height="400" loading="lazy">
<em>requestAnimationFrame() v.s. setInterval()</em></p>
<p>This way, your code has a higher chance of finishing within the 10ms time to leave enough time for the web browser to do its internal stuff in the total duration of 16.7ms.</p>
<p>So instead of:</p>
<pre><code class="lang-javascript"><span class="hljs-built_in">setInterval</span>(
    <span class="hljs-function">() =&gt;</span> {
        <span class="hljs-comment">// make some change</span>
    },
    <span class="hljs-number">16.7</span>
)
</code></pre>
<p>You can do:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> animateSomething = <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params"></span>) </span>{
    <span class="hljs-comment">// make some change</span>

    <span class="hljs-comment">// Next call</span>
    requestAnimationFrame(animateSomething)
}

<span class="hljs-comment">// First manual call to start the animation</span>
requestAnimationFrame(animateSomething)
</code></pre>
<p>Another benefit of using <code>requestAnimationFrame</code> is that the browser can run your animation more efficiently.</p>
<p>For instance, if the user switches to another tab, the browser will pause the animation. This reduces the processing time and battery life.</p>
<h2 id="heading-how-to-optimize-an-animation-see-it-in-action">How to Optimize an Animation – See it in Action</h2>
<p>As promised, it's time to do some experiments.</p>
<p>For this experiment, I've created an animation in two different ways. </p>
<p>The animation is about an airplane flying over the horizon at sunset.</p>
<p>In the first approach, I've used all the layout-triggering properties (left &amp; top) without worrying about any performance trade-offs.</p>
<p>I've also used <code>setInterval</code> with 16.7ms frequency for my timed loop.</p>
<p>In the second approach, I refactored the code and used compositor-only styles. I also promoted my moving element (the airplane) with the <code>will-change</code> property to make sure it'll have its own layer. </p>
<p>I also replaced <code>setInterval</code> with <code>requestAnimationFrame</code> for better timing.</p>
<p>To simulate the airplane's movement, I've used the <code>Math.sine()</code> with some adjustments. The traveling path is also drawn with an SVG-based sine graph.</p>
<p>Here's the <a target="_blank" href="https://codepen.io/lavary/pen/YzEpLbE">CodePen link</a> to the first approach:</p>
<div class="embed-wrapper">
        <iframe width="100%" height="350" src="https://codepen.io/lavary/embed/YzEpLbE" style="aspect-ratio: 16 / 9; width: 100%; height: auto;" title="CodePen embed" scrolling="no" allowtransparency="true" allowfullscreen="true" loading="lazy"></iframe></div>
<p>And <a target="_blank" href="https://codepen.io/lavary/pen/eYvOojp">the second approach</a> with layer promotion (<code>will-change: transform</code>) compositor-only styles (<code>transform: translate()</code>) , and <code>requestAnimationFrame</code>:</p>
<div class="embed-wrapper">
        <iframe width="100%" height="350" src="https://codepen.io/lavary/embed/eYvOojp" style="aspect-ratio: 16 / 9; width: 100%; height: auto;" title="CodePen embed" scrolling="no" allowtransparency="true" allowfullscreen="true" loading="lazy"></iframe></div>
<h3 id="heading-lets-compare-the-two-approaches">Let's compare the two approaches</h3>
<p>One of the metrics you can use is the frame rate. It helps you monitor the consistency of the frames during a motion.</p>
<p>Take a look at the below recording:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/02/animation-paint.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>You can see the FPS meter in the image above (top left of the screenshot). Even though the screenshot shows 90 fps, the yellow/red bars indicate some frames were missed or delayed.</p>
<p>The Event Log (bottom right) shows all the steps were involved during the recording: <strong>Recalculate Style &gt; Layout &gt; Paint &gt; Composite layers.</strong></p>
<p>To enable the FPS meter, while in Chrome DevTools, hold ⌘+<strong>⇧</strong>+P (or Ctrl+<strong>⇧</strong> Shift+P) to activate the Command Palette. Then, type <code>FPS meter</code> and choose Show frames per second (FPS) meter.</p>
<p>And here's a quick guide on reading it:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/02/FPS-meter.png" alt="Image" width="600" height="400" loading="lazy">
<em>FPS meter</em></p>
<p>Now, let's measure the second approach:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/02/animation-composite.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>In the second recording, the average FPS is 118.8 with no missed or dropped frames.</p>
<p>The event log also confirms no layout and paintwork were necessary, and the compositor did the whole thing (Recalculate Style → Composite Layer).</p>
<p>You can also use Chrome's <strong>Paint Flashing</strong> tool to see what parts of the page are being repainted. This is useful to detect unwanted paintwork during user interactions.</p>
<p>In the airplane example, the area being repainted (the moving airplane) is displayed as green-bordered rectangles. </p>
<div class="embed-wrapper">
        <iframe width="560" height="315" src="https://www.youtube.com/embed/1rd2aemUGCE" style="aspect-ratio: 16 / 9; width: 100%; height: auto;" title="YouTube video player" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen="" loading="lazy"></iframe></div>
<p>Enabling paint flashing for the second approach won't show anything as there's no paintwork during the animation.</p>
<p>The question is can a user notice this improvement? </p>
<p>Let's see.</p>
<p>Here are both animations in slow motion (10x slowed down) to see if there's any change:</p>
<div class="embed-wrapper">
        <iframe width="560" height="315" src="https://www.youtube.com/embed/X05WCbC-ITY" style="aspect-ratio: 16 / 9; width: 100%; height: auto;" title="YouTube video player" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen="" loading="lazy"></iframe></div>
<p>I'll leave it to your judgment.</p>
<h2 id="heading-too-long-didnt-read">Too long; didn't read?</h2>
<p>To have smooth motions on your page, all you need to do is to make sure:</p>
<ul>
<li>Fames are delivered on time</li>
<li>Frames are delivered on time <strong>consistently</strong></li>
</ul>
<p>And here's a checklist to achieve it:</p>
<ul>
<li>Make sure your JavaScript changes happen at the beginning of each frame by using <code>requestAnimationFrame</code>. </li>
<li>When changing the dimension of an element, use <code>transform:scale()</code>  over <code>height</code> &amp; <code>width</code>.</li>
<li>To move the elements around, always use <code>transform: translate()</code> over coordinates (<code>top</code>, <code>right</code>, <code>bottom</code>, and <code>left</code>).</li>
<li>Reduce paint complexity by using simple CSS styles over expensive ones. For instance, if possible, use solid colors over gradients or shadows.</li>
<li>Normalize using the transitions on mobile versions. Even though the computing capacity of mobile phones is limited, mobile-version UX often contains more transitions/effects owing to their small screen.</li>
<li>Use your browser's developer tools to diagnose animation performance. Use tools such as Paint Flashing and FPS meter to fine-tune your animations.</li>
<li>Use DevTool's Performance panel to see how your code runs on lower-end devices.</li>
</ul>
<p>You can apply these micro-optimizations when doing any type of change. Whether you're making JavaScript or CSS animation, or you're just making a one-off change with JavaScript.</p>
<p>This was the opening line of this guide:</p>
<blockquote>
<p>What if I told you web pages were interactive animations played back by your web browser.</p>
</blockquote>
<p>But, what if I tell you now this was just the tip of the iceberg?!</p>
<p>Don't worry, you can already do a lot to make your web pages look pleasant to the eyes.</p>
<p>If you want to take your performance knowledge to the next level, I maintain a <a target="_blank" href="https://www.decodingweb.dev/courses/web-performance">dedicated page to collect web performance resources from various creators</a>. Check it out!</p>
<p>If you have any questions or comments or there's something I missed (or I've gotten wrong), please feel free to fire away at <strong>@lavary_</strong> on Twitter<em>.</em></p>
<p>Thanks for reading!</p>
<h3 id="heading-attributions">Attributions:</h3>
<ul>
<li>Post image: <strong><a target="_blank" href="https://commons.wikimedia.org/wiki/File:Antics_2-D_Animation_infobox_screenshot.png">Antics 2-D Animation of White Rabbit</a></strong> (image was cropped) by <strong>Antics Workshop</strong> under <strong><a target="_blank" href="https://creativecommons.org/licenses/by-sa/3.0/">CC BY-SA 3.0</a></strong> </li>
</ul>
 ]]>
                </content:encoded>
            </item>
        
    </channel>
</rss>
