<?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[ Franklin Okolie - 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[ Franklin Okolie - freeCodeCamp.org ]]>
            </title>
            <link>https://www.freecodecamp.org/news/</link>
        </image>
        <generator>Eleventy</generator>
        <lastBuildDate>Sun, 24 May 2026 16:29:55 +0000</lastBuildDate>
        <atom:link href="https://www.freecodecamp.org/news/author/developeraspire/rss.xml" rel="self" type="application/rss+xml" />
        <ttl>60</ttl>
        
            <item>
                <title>
                    <![CDATA[ How to Use the Ternary Operator in JavaScript – Explained with Examples ]]>
                </title>
                <description>
                    <![CDATA[ Tired of bulky if-else statements? JavaScript's ternary operator offers a powerful solution. This handy tool lets you condense complex conditional logic into a single line, making your code cleaner, more elegant, and efficient. In this article, we'll... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/javascript-ternary-operator-explained/</link>
                <guid isPermaLink="false">66ba5977efd5e6f1088c72aa</guid>
                
                    <category>
                        <![CDATA[ JavaScript ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Franklin Okolie ]]>
                </dc:creator>
                <pubDate>Tue, 27 Feb 2024 13:04:50 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2024/02/ternary-operator-1.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Tired of bulky if-else statements? JavaScript's ternary operator offers a powerful solution. This handy tool lets you condense complex conditional logic into a single line, making your code cleaner, more elegant, and efficient.</p>
<p>In this article, we'll take a deep dive into the ternary operator, understanding its syntax and showcasing real-world examples to help you understand how it works to harness its full potential.</p>
<h2 id="heading-here-is-what-well-cover">Here is What We'll Cover:</h2>
<ol>
<li><a class="post-section-overview" href="#heading-what-is-a-ternary-operator">What is A Ternary Operator?</a></li>
<li><a class="post-section-overview" href="#heading-how-to-use-the-ternary-operator">How to Use the Ternary Operator</a></li>
<li><a class="post-section-overview" href="#heading-how-to-refactor-if-else-statements-to-ternary-operator">How to Refactor if-else Statements to Ternary operator</a></li>
<li><a class="post-section-overview" href="#heading-how-to-chain-ternary-operators">How to Chain Ternary Operators</a></li>
<li><a class="post-section-overview" href="#heading-best-practices-when-using-the-ternary-operator">Best Practices when using the Ternary Operator</a></li>
<li><a class="post-section-overview" href="#heading-conclusion">Conclusion</a></li>
</ol>
<h2 id="heading-what-is-a-ternary-operator">What is A Ternary Operator?</h2>
<p>A ternary operator is a conditional operator in JavaScript that evaluates a conditional expression and returns either a truthy or falsy value.</p>
<p>To understand how this works, let's take a closer look at its syntax below:</p>
<pre><code class="lang-js">conditionalExpression ? truthyValue : falsyValue
</code></pre>
<p>From the syntax above, the <code>condionalExpression</code> is the expression that serves as the evaluation point, determining either a truthy or falsy value. </p>
<p>Following the <code>?</code> (question mark), the value provided is returned in case the expression evaluates to truthy, whereas the value following the <code>:</code> (colon) is returned if the expression results in a falsy outcome.</p>
<p>The <code>truthyValue</code> and <code>falsyValue</code> can be anything in JavaScript. It can encompass various entities such as functions, values stored in variables, objects, numbers, strings, and more. The ternary operator grants you the flexibility to return any desired value, offering versatility in your code.</p>
<h2 id="heading-how-to-use-the-ternary-operator">How to Use the Ternary Operator</h2>
<p>Now that we've examined the syntax and its functionality, let's explore how to use the ternary operator to deepen our understanding.</p>
<p>Consider this scenario: we're building a gaming platform that only allows users that are aged 18 and above. We'll design a function to check a user's age. If they're under 18, they'll be denied access; otherwise, they'll gain entry to the platform.</p>
<pre><code class="lang-js"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">canAccessPlatform</span>(<span class="hljs-params">age</span>) </span>{
  <span class="hljs-keyword">const</span> shouldAccess = age &gt;= <span class="hljs-number">18</span> ? <span class="hljs-literal">true</span> : <span class="hljs-literal">false</span>;

  <span class="hljs-keyword">return</span> shouldAccess;
}
</code></pre>
<p>From the code snippet above, we created a function, <code>canAccessPlatform</code>, which evaluates whether a user, represented by their <code>age</code> parameter, meets the requirement to access the platform. </p>
<p>It utilizes a ternary operator to determine if the age is 18 or older, assigning <code>true</code> to <code>shouldAccess</code> if the condition is met, and <code>false</code> otherwise. Finally, it returns the value of <code>shouldAccess</code>, indicating whether the user can access the platform or not.</p>
<p>If the age is 18 or older, the expression becomes true, so the operator returns true after the <code>?</code>. Otherwise, it returns false. This result is saved in a variable and then returned from the function. </p>
<p>While this basic use case simplifies code and improves readability by replacing unnecessary if-else blocks, it's important to use it sparingly to avoid cluttering and complicating your code. Later, we'll discuss best practices for using the ternary operator.</p>
<p>Here's another example illustrating the use of the ternary operator. We'll create a function to determine whether a number is even or odd. Check out the code snippet below:</p>
<pre><code class="lang-js"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">checkEvenOrOdd</span>(<span class="hljs-params">number</span>) </span>{
  <span class="hljs-keyword">const</span> result = number % <span class="hljs-number">2</span> === <span class="hljs-number">0</span> ? <span class="hljs-string">"even"</span> : <span class="hljs-string">"odd"</span>;
  <span class="hljs-keyword">return</span> result;
}

<span class="hljs-comment">// Usage:</span>
<span class="hljs-built_in">console</span>.log(checkEvenOrOdd(<span class="hljs-number">4</span>)); <span class="hljs-comment">// Output: "even"</span>
<span class="hljs-built_in">console</span>.log(checkEvenOrOdd(<span class="hljs-number">7</span>)); <span class="hljs-comment">// Output: "odd"</span>
</code></pre>
<p>From the code snippet above:</p>
<ul>
<li>We define a function <code>checkEvenOrOdd</code> that takes a <code>number</code> parameter.</li>
<li>Inside the function, we use the ternary operator to check if the number is even or odd.</li>
<li>If the number modulo 2 equals 0 (meaning it's divisible by 2 with no remainder), then the condition evaluates to true, and the string "even" is assigned to the <code>result</code> variable.</li>
<li>If the condition evaluates to false (meaning the number is odd), the string "odd" is assigned to <code>result</code>.</li>
<li>Finally, the function returns the value of <code>result</code>, which indicates whether the number is even or odd.</li>
</ul>
<p>This code shows how the ternary operator quickly checks if a number is even or odd, making the code easier to read and understand.</p>
<h2 id="heading-how-to-refactor-if-else-statements-to-ternary-operator">How to Refactor if-else Statements to Ternary Operator</h2>
<p>An advantage of the ternary operator is avoiding unnecessary if-else blocks, which can complicate code readability and maintenance. In this section, we'll refactor some if-else statements into ternary operations, providing a clearer understanding of how to use ternary operators effectively.</p>
<p>Let's start with our first example:</p>
<pre><code class="lang-js"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">decideActivity</span>(<span class="hljs-params">weather</span>) </span>{
  <span class="hljs-keyword">let</span> activity;

  <span class="hljs-keyword">if</span> (weather === <span class="hljs-string">"sunny"</span>) {
    activity = <span class="hljs-string">"go out"</span>;
  } <span class="hljs-keyword">else</span> {
    activity = <span class="hljs-string">"stay in"</span>;
  }

  <span class="hljs-built_in">console</span>.log(activity);
}

<span class="hljs-comment">// Usage</span>
<span class="hljs-built_in">console</span>.log(decideActivity(<span class="hljs-string">"raining"</span>)); <span class="hljs-comment">// Output: "stay in"</span>
<span class="hljs-built_in">console</span>.log(decideActivity(<span class="hljs-string">"snowing"</span>)); <span class="hljs-comment">// Output: "stay in"</span>
<span class="hljs-built_in">console</span>.log(decideActivity(<span class="hljs-string">"sunny"</span>)); <span class="hljs-comment">// Output: "go out"</span>
</code></pre>
<p>This function, <code>decideActivity</code>, takes a <code>weather</code> parameter and determines the appropriate activity based on the weather condition. </p>
<p>If the weather is "sunny", it suggests to "go out". Otherwise, it advises to "stay in". When we call the function with different weather conditions like "raining" or "snowing", it outputs the corresponding activity recommendation using <code>console.log()</code>. </p>
<p>For instance, calling <code>decideActivity("raining")</code> will output "stay in". Similarly, <code>decideActivity("snowing")</code> also outputs "stay in". When <code>decideActivity("sunny")</code> is called, it outputs "go out". This straightforward function helps decide on activities based on the weather condition provided.</p>
<p>Now, we can refactor these blocks of code to make them look simpler and neater. Let's see how to do that below:</p>
<pre><code class="lang-js"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">decideActivity</span>(<span class="hljs-params">weather</span>)</span>{
   <span class="hljs-keyword">const</span> activity = weather === <span class="hljs-string">"sunny"</span> ? <span class="hljs-string">"go out"</span> ? <span class="hljs-string">"stay in"</span>;

   <span class="hljs-built_in">console</span>.log(activity)

}

<span class="hljs-comment">// Usage</span>
<span class="hljs-built_in">console</span>.log(decideActivity(<span class="hljs-string">"raining"</span>)); <span class="hljs-comment">// Output: "stay in"</span>
<span class="hljs-built_in">console</span>.log(decideActivity(<span class="hljs-string">"snowing"</span>)); <span class="hljs-comment">// Output: "stay in"</span>
<span class="hljs-built_in">console</span>.log(decideActivity(<span class="hljs-string">"sunny"</span>)); <span class="hljs-comment">// Output: "go out"</span>
</code></pre>
<p>From the code sample above, this function, <code>decideActivity</code>, uses the ternary operator to quickly determine the activity based on the weather condition. It checks if the weather is "sunny" and assigns "go out" if true, otherwise "stay in". </p>
<p>We've simplified the if-else statements into a one-liner ternary operator. This makes our code cleaner, clearer, and easier to read.</p>
<p>Let take a look at another example:</p>
<pre><code class="lang-js"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">checkNumber</span>(<span class="hljs-params">number</span>) </span>{
  <span class="hljs-keyword">let</span> result;
  <span class="hljs-keyword">if</span> (number &gt; <span class="hljs-number">0</span>) {
    result = <span class="hljs-string">"positive"</span>;
  } <span class="hljs-keyword">else</span> {
    result = <span class="hljs-string">"non-positive"</span>;
  }
  <span class="hljs-keyword">return</span> result;
}

<span class="hljs-comment">// Usage</span>
<span class="hljs-built_in">console</span>.log(checkNumber(<span class="hljs-number">5</span>)); <span class="hljs-comment">// Output: "positive"</span>
<span class="hljs-built_in">console</span>.log(checkNumber(<span class="hljs-number">-2</span>)); <span class="hljs-comment">// Output: "non-positive"</span>
</code></pre>
<p>Let's explain what the code above is doing:</p>
<ul>
<li><strong>Function Definition</strong>: We begin by defining a function named <code>checkNumber</code> that takes a single parameter called <code>number</code>.</li>
<li><strong>Variable Declaration</strong>: Inside the function, we declare a variable named <code>result</code> without assigning any value to it yet. This variable will store the result of our check.</li>
<li><strong>Conditional Statement (if-else)</strong>: We have a conditional statement that checks whether the <code>number</code> parameter is greater than 0.</li>
<li>If the condition is true (meaning the number is positive), we assign the string "positive" to the <code>result</code> variable.</li>
<li>If the condition is false (meaning the number is not positive, (meaning it is either negative or zero), we assign the string "non-positive" to the <code>result</code> variable.</li>
<li><strong>Return Statement</strong>: Finally, we return the value stored in the <code>result</code> variable.</li>
<li><strong>Function Calls</strong>:We then call the <code>checkNumber</code> function twice with different arguments: 5 and -2.</li>
</ul>
<p>When we call <code>checkNumber(5)</code>, the function returns "positive", which is then logged to the console.</p>
<p>Similarly, when we call <code>checkNumber(-2)</code>, the function returns "non-positive", which is again logged to the console.</p>
<p>This function efficiently determines whether a number is positive or non-positive and provides the appropriate result based on the condition.</p>
<p>Let's simplify and improve the code by rewriting it using a ternary operator.</p>
<pre><code class="lang-js"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">checkNumber</span>(<span class="hljs-params">number</span>) </span>{
  <span class="hljs-keyword">const</span> result = number &gt; <span class="hljs-number">0</span> ? <span class="hljs-string">"positive"</span> : <span class="hljs-string">"non-positive"</span>;
  <span class="hljs-keyword">return</span> result;
}

<span class="hljs-comment">// Usage</span>
<span class="hljs-built_in">console</span>.log(checkNumber(<span class="hljs-number">5</span>)); <span class="hljs-comment">// Output: "positive"</span>
<span class="hljs-built_in">console</span>.log(checkNumber(<span class="hljs-number">-2</span>)); <span class="hljs-comment">// Output: "non-positive"</span>
</code></pre>
<p>Great job! By refactoring the function and utilizing the ternary operator for conditional evaluation, we've achieved cleaner, more concise, and readable code.</p>
<p>This code, using the ternary operator, feels more concise and elegant. It efficiently determines if a number is positive or non-positive, making the code cleaner and easier to understand. When we call <code>checkNumber(5)</code>, it returns "positive",  while <code>checkNumber(-2)</code> returns "non-positive". Overall, the ternary operator enhances the code's readability.</p>
<h2 id="heading-how-to-chain-ternary-operators">How to Chain Ternary Operators</h2>
<p>When dealing with conditional checks, sometimes a single condition isn't enough. In such cases, we use 'else-if' statements alongside 'if/else' to incorporate multiple conditions. </p>
<p>Let's take a look at the syntax:</p>
<pre><code class="lang-js"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">exampleFn</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">return</span> conditionalExpression1
    ? value1
    : conditionalExpression2
    ? value2
    : conditionalExpression3
    ? value3
    : value4;
}
</code></pre>
<p>This can be translated into an if/else chain:</p>
<pre><code class="lang-js"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">exampleFn</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">if</span> (conditionalExpression1) {
    <span class="hljs-keyword">return</span> value1;
  } <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (conditionalExpression2) {
    <span class="hljs-keyword">return</span> value2;
  } <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (conditionalExpression3) {
    <span class="hljs-keyword">return</span> value3;
  } <span class="hljs-keyword">else</span> {
    <span class="hljs-keyword">return</span> value4;
  }
}
</code></pre>
<p>Let's explore an example below:</p>
<pre><code class="lang-js"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">checkNumber</span>(<span class="hljs-params">number</span>) </span>{
  <span class="hljs-keyword">let</span> message;

  <span class="hljs-keyword">if</span> (number &gt; <span class="hljs-number">0</span>) {
    message = <span class="hljs-string">"Positive"</span>;
  } <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (number === <span class="hljs-number">0</span>) {
    message = <span class="hljs-string">"Zero"</span>;
  } <span class="hljs-keyword">else</span> {
    message = <span class="hljs-string">"Negative"</span>;
  }

  <span class="hljs-keyword">return</span> message;
}

<span class="hljs-comment">// Usage</span>
<span class="hljs-built_in">console</span>.log(checkNumber(<span class="hljs-number">5</span>)); <span class="hljs-comment">// Output: "Positive"</span>
<span class="hljs-built_in">console</span>.log(checkNumber(<span class="hljs-number">0</span>)); <span class="hljs-comment">// Output: "Zero"</span>
<span class="hljs-built_in">console</span>.log(checkNumber(<span class="hljs-number">-3</span>)); <span class="hljs-comment">// Output: "Negative"</span>
</code></pre>
<p>This code above defines a function called <code>checkNumber</code> that takes a <code>number</code> parameter and determines its status (positive, zero, or negative). It utilizes an if-else block with one else-if statement to evaluate the number's value. If the number is greater than 0, it's considered positive and if it's equal to 0, it's zero. Otherwise, it's negative. The function returns the result.</p>
<p>Let's refactor this code using a ternary operator to achieve the same functionality.</p>
<pre><code class="lang-js"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">checkNumber</span>(<span class="hljs-params">number</span>) </span>{
  <span class="hljs-keyword">return</span> number &gt; <span class="hljs-number">0</span> ? <span class="hljs-string">"Positive"</span> : number === <span class="hljs-number">0</span> ? <span class="hljs-string">"Zero"</span> : <span class="hljs-string">"Negative"</span>;
}

<span class="hljs-comment">// Usage</span>
<span class="hljs-built_in">console</span>.log(checkNumber(<span class="hljs-number">5</span>)); <span class="hljs-comment">// Output: "Positive"</span>
<span class="hljs-built_in">console</span>.log(checkNumber(<span class="hljs-number">0</span>)); <span class="hljs-comment">// Output: "Zero"</span>
<span class="hljs-built_in">console</span>.log(checkNumber(<span class="hljs-number">-3</span>)); <span class="hljs-comment">// Output: "Negative"</span>
</code></pre>
<p>That's it! We've refactored the function, and upon closer examination, we can observe that the operators are chained together. Now, let's explore how the chained ternary operator works in the <code>checkNumber</code> function.</p>
<p>In the first ternary operator:</p>
<ul>
<li>The first part <code>number &gt; 0</code> checks if the number is greater than 0.</li>
<li>If it's true, the expression returns "Positive".</li>
</ul>
<p>In the second ternary operator (chained):</p>
<ul>
<li>If the first condition is false (meaning the number is not greater than 0), it moves to the next part of the expression: <code>number === 0</code>.</li>
<li>This part checks if the number is equal to 0.</li>
<li>If it's true, the expression returns "Zero".</li>
</ul>
<p>And the default value:</p>
<ul>
<li>If neither of the above conditions is true (meaning the number is not greater than 0 and not equal to 0), it defaults to the last part of the expression: <code>"Negative"</code>.</li>
<li>This part acts as the default value if none of the preceding conditions are met.</li>
</ul>
<p>In summary, the chained ternary operator evaluates multiple conditions in a single line of code. It checks each condition sequentially, and the first condition that evaluates to true determines the result of the entire expression. This allows for concise and efficient conditional logic.</p>
<p>Let's examine another example of a chained ternary operator.</p>
<pre><code class="lang-js"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getDrink</span>(<span class="hljs-params">age</span>) </span>{
  <span class="hljs-keyword">return</span> age &gt;= <span class="hljs-number">21</span>
    ? <span class="hljs-string">"Enjoy a cocktail"</span>
    : age &gt;= <span class="hljs-number">18</span>
    ? <span class="hljs-string">"Have a beer"</span>
    : age &gt;= <span class="hljs-number">16</span>
    ? <span class="hljs-string">"Grab a soft drink"</span>
    : <span class="hljs-string">"Sorry, you're too young to drink"</span>;
}

<span class="hljs-comment">// Usage</span>
<span class="hljs-built_in">console</span>.log(getDrink(<span class="hljs-number">25</span>)); <span class="hljs-comment">// Output: "Enjoy a cocktail"</span>
<span class="hljs-built_in">console</span>.log(getDrink(<span class="hljs-number">19</span>)); <span class="hljs-comment">// Output: "Have a beer"</span>
<span class="hljs-built_in">console</span>.log(getDrink(<span class="hljs-number">16</span>)); <span class="hljs-comment">// Output: "Grab a soft drink"</span>
<span class="hljs-built_in">console</span>.log(getDrink(<span class="hljs-number">10</span>)); <span class="hljs-comment">// Output: "Sorry, you're too young to drink"</span>
</code></pre>
<p>In the given code sample, the ternary operators are chained together to provide different drink suggestions based on the age provided. Each conditional expression in the chain evaluates a specific age range. </p>
<p>If the first condition is true (truthy), it returns 'Enjoy a cocktail'. If false (falsy), it moves to the next conditional expression, and so on. This chaining process continues until a condition evaluates to true. If none of the conditions in the chain are true, the last value is returned as a fallback, similar to the 'else' block in an if/else statement.</p>
<p>The concept of 'chaining' ternary operators involves linking conditional expressions based on the value of the previous expression. This can be compared to the <code>else if</code> structure in an <code>if/else</code> statement, providing a concise way to handle multiple conditions in JavaScript. </p>
<h2 id="heading-best-practices-when-using-the-ternary-operator">Best Practices when Using the Ternary Operator</h2>
<p>Using the ternary operator efficiently can significantly enhance code readability and conciseness. In this section, we'll explore key best practices for utilizing the ternary operator effectively. </p>
<ol>
<li><strong>Keep it simple and readable</strong>: Write concise expressions that are easy to understand at a glance. Avoid nesting too many ternary operators or writing overly complex conditions. </li>
<li><strong>Use for simple assignments:</strong> Ternary operators are ideal for simple assignments where there are only two possible outcomes based on a condition. For more complex scenarios, consider using <code>if/else</code> statements.</li>
<li><strong>Know when to use it</strong>: Use the ternary operator when you need to perform a simple conditional check and assign a value based on the result. It's particularly useful for assigning default values or determining the value of a variable based on a condition.</li>
<li><strong>Test thoroughly</strong>: Test your code thoroughly to ensure that the ternary operator behaves as expected under different conditions. Check for edge cases and validate the correctness of the assigned values.</li>
<li><strong>Avoid nested ternaries:</strong> While chaining ternaries is possible, excessive nesting can lead to code that is difficult to read. Prefer clarity and consider using <code>if/else</code> for complex conditions.</li>
<li><strong>Keep ternaries short:</strong> Aim to keep ternary expressions short and concise. Long ternaries can be difficult to read and understand, leading to code maintenance challenges.</li>
</ol>
<p>These best practices outline guidelines for effectively utilizing the ternary operator. While they are not strict rules, they offer valuable insights to enhance the clarity and readability of your code.</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>As we conclude this article, you've gained a comprehensive understanding of the ternary operator—its application in daily coding tasks, converting if/else statements, chaining operators, and best practices. I'm confident that you've acquired valuable insights that will enhance your coding practices using the ternary operator.</p>
<p>Thank you for reading, and see you next time!</p>
<h3 id="heading-contact-information">Contact information</h3>
<p>Would you like to get in touch with me? Don't hesitate to reach out through any of the following channels:</p>
<ul>
<li>Twitter / X: <a target="_blank" href="https://twitter.com/developeraspire">@developeraspire</a></li>
<li>Email: developeraspire5@gmail.com</li>
</ul>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Build a Custom HTML5 Video Player Using TailwindCSS and JavaScript ]]>
                </title>
                <description>
                    <![CDATA[ HTML5 comes equipped with a native video player. It's shipped with a simple user interface, functionality, and some basic controls in the browser. And while the functionality of the default video player via the browser works perfectly, the user inter... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/build-a-custom-video-player-using-javascript-and-tailwind-css/</link>
                <guid isPermaLink="false">66ba596b256e9dbeab31aaaf</guid>
                
                    <category>
                        <![CDATA[ JavaScript ]]>
                    </category>
                
                    <category>
                        <![CDATA[ tailwind ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Franklin Okolie ]]>
                </dc:creator>
                <pubDate>Tue, 13 Feb 2024 15:14:21 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2024/02/how-to-build-a-custom-video-player-using-tailwindcss-and-javascript.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>HTML5 comes equipped with a native video player. It's shipped with a simple user interface, functionality, and some basic controls in the browser. And while the functionality of the default video player via the browser works perfectly, the user interface isn't so beautiful and fancy, and it's just not generally aesthetically pleasing. </p>
<p>For this reason, most modern web applications and platforms like Udemy, Netflix, YouTube, and Amazon Prime don't ship the default built-in HTML5 video player to their users. Instead, they build their own customized versions with a sleek user interface to make their platforms more attractive and user-friendly.</p>
<p>If you have ever been curious how these companies and web platforms are able to pull off such feat, then this article is for you.</p>
<p>You'll get some hands-on experience while following along with a step-by-step guide that teaches you how you can build and customize your own HTML5 video player. You'll learn how to customize the user interface, extend the functionality, and build your own fantastic custom controls and features.</p>
<p>You'll also learn how to build all this using nothing other than the native Video API provided by JavaScript in the browser – no external libraries or tools required.</p>
<h2 id="heading-prerequisites">Prerequisites</h2>
<ul>
<li>Fundamental knowledge of HTML5 and CSS</li>
<li>Fundamental knowledge of Tailwind CSS</li>
<li>Fundamental knowledge of JavaScript (ES6)</li>
<li>A code editor of your choice</li>
<li>A browser that supports modern features of JavaScript (for example Chrome or Mozilla Firefox)</li>
</ul>
<h2 id="heading-heres-what-well-cover">Here's what we'll cover:</h2>
<ol>
<li><a class="post-section-overview" href="#heading-getting-started">Getting Started</a></li>
<li><a class="post-section-overview" href="#heading-how-to-set-up-the-development-environment">How to Set Up the Development Environment</a></li>
<li><a class="post-section-overview" href="#heading-how-to-build-a-customized-ui-using-tailwind-css">How to Build a Customized UI using Tailwind CSS</a></li>
<li><a class="post-section-overview" href="#heading-how-to-implement-the-play-and-pause-functionality">How to Implement the Play and Pause Functionality</a></li>
<li><a class="post-section-overview" href="#heading-how-to-implement-the-rewind-and-fast-forward-functionality">How to Implement the Rewind and Fast Forward Functionality</a></li>
<li><a class="post-section-overview" href="#heading-how-to-implement-the-mute-and-unmute-functionality">How to Implement the Mute and Unmute Functionality</a></li>
<li><a class="post-section-overview" href="#heading-how-to-update-the-progress-bar-relative-to-the-video-time">How to Update the Progress Bar Relative to the Video Time</a></li>
<li><a class="post-section-overview" href="#heading-how-to-implement-the-seeking-functionality">How to Implement the Seeking Functionality</a></li>
<li><a class="post-section-overview" href="#heading-how-to-add-keyboard-navigation-for-accesibility">How to Implement Keyboard Navigations for Accessibility</a></li>
<li><a class="post-section-overview" href="#heading-where-to-go-from-here">Where to Go from Here</a></li>
<li><a class="post-section-overview" href="#heading-conclusion">Conclusion</a></li>
</ol>
<h2 id="heading-getting-started">Getting Started</h2>
<p>In this article, we will be using Tailwind CSS as the styling tool to build out the custom video player UI. We'll also use JavaScript to build out the functionality of the controls.</p>
<p>Note that using Tailwind CSS is optional, as any styling tool will suffice here like SCSS, CSS, styled-components and so on – it's totally up to you.</p>
<p>I've split this tutorial into different sections, each addressing a specific aspect of the custom video player functionality. Each new section will build upon the previous ones to complete the player. By the end of the article, you will have a fully functional HTML5 custom video player.</p>
<p>In this tutorial, we'll concentrate on specific features of the video player. These features will offer opportunities and ideas for building additional functionalities. The features we'll cover are:</p>
<ul>
<li>Play and Pause</li>
<li>Rewind and Fast Forward</li>
<li>Mute and Unmute</li>
<li>Video Seeking</li>
<li>Keyboard navigations (utilizing the Spacebar for play and pause, and the Arrow keys for rewind and fast forward).</li>
</ul>
<p>We won't address responsive design here, as we won't be focusing on making the video player mobile responsive. This omission should present a challenge and a learning opportunity for you.</p>
<p>Now, let's delve into setting up our development environment so we can start building.</p>
<h2 id="heading-how-to-set-up-the-development-environment">How to Set Up the Development Environment</h2>
<p>The initial step is to setup an efficient development environment to ensure smooth workflow. We'll use <a target="_blank" href="https://vitejs.dev/">Vite</a> for this purpose. </p>
<p>Before progressing to the next part of this section, make sure that you have <a target="_blank" href="https://nodejs.org/en">NodeJS</a> and <a target="_blank" href="https://www.npmjs.com/">NPM</a> or <a target="_blank" href="https://yarnpkg.com/">Yarn</a> installed on your computer, as they are necessary for installing tools and setting up your development environment seamlessly.</p>
<h3 id="heading-how-to-setup-the-project-with-vite">How to setup the project with Vite</h3>
<p>To scaffold a project in Vite, open your terminal and type in the following command:</p>
<pre><code class="lang-bash">yarn create vite
</code></pre>
<p>Vite will guide you in configuring and selecting the appropriate tools for your development environment. </p>
<p>The first step is to choose a project name – you have the freedom to choose any name you prefer. In this article, I'll be using "html5-video-player" as the project name.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/02/image-81.png" alt="Image" width="600" height="400" loading="lazy">
<em>Terminal output after running 'yarn create vite' command</em></p>
<p>The next step is selecting the project framework. This project will be written in pure JavaScript, so choose "Vanilla" and then select "JavaScript" on the next prompt.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/02/image-82.png" alt="Image" width="600" height="400" loading="lazy">
<em>Terminal output after inputting a project name, asking to select a framework for the project</em></p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/02/image-83.png" alt="Image" width="600" height="400" loading="lazy">
<em>Terminal output afte selecting the 'Vanilla' framwork</em></p>
<p>Now, Vite has successfully set up your environment using the selected tools. It's time to install the dependencies necessary for Vite to function properly. Follow the instructions provided by Vite in the CLI.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/02/image-84.png" alt="Image" width="600" height="400" loading="lazy">
<em>Terminal showing a success message on setting up the environment</em></p>
<p>If you named your project like mine, then run the command below exactly as it is. If you chose a different name, simply substitute my project name with yours and proceed in the same manner.</p>
<pre><code class="lang-bash"><span class="hljs-built_in">cd</span> html5-video-player
</code></pre>
<p>This command will navigate to the project directory where your development environment resides. From there, you can proceed to install the dependencies.</p>
<pre><code class="lang-bash">yarn
</code></pre>
<p>Once the dependencies are installed, let's proceed to the next step, which involves setting up Tailwind CSS as our styling tool. This process is straightforward, similar to how we set up Vite.</p>
<p>Open your terminal and execute the following commands:</p>
<pre><code class="lang-bash">yarn add -D tailwindcss postcss autoprefixer
</code></pre>
<p>This will install Tailwind CSS, our styling tool, as well as PostCSS and Autoprefixer. These tools will assist Tailwind CSS in functioning effectively within your project. </p>
<p>The next command involves setting up the configuration files for Tailwind CSS and PostCSS.</p>
<p>Open your local terminal once again and type in the following command:</p>
<pre><code class="lang-bash">npx tailwindcss init
</code></pre>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/02/image-85.png" alt="Image" width="600" height="400" loading="lazy">
<em>Creating Tailwind CSS configuration file.</em></p>
<p>As mentioned in the command message, a file named <code>tailwind.config.js</code> will be generated at the root of the project folder. This file will contain your configuration for styling, including settings for fonts, colors, plugins, and more. For further details, refer to the <a target="_blank" href="https://tailwindcss.com/">TailwindCSS documentation</a>.</p>
<p>Open the Tailwind CSS configuration file that was generated in your code editor and make the following edits to it:</p>
<pre><code class="lang-js"><span class="hljs-comment">/** <span class="hljs-doctag">@type <span class="hljs-type">{import('tailwindcss').Config}</span> </span>*/</span>
<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> {
  <span class="hljs-attr">content</span>: [<span class="hljs-string">'./index.html'</span>],
  <span class="hljs-attr">theme</span>: {
    <span class="hljs-attr">extend</span>: {},
  },
  <span class="hljs-attr">plugins</span>: [],
}
</code></pre>
<p>Here, we simply edited the <code>content</code> key to specify the file where TailwindCSS should read for Tailwind CSS classes. This file happens to be the <code>index.html</code> file, where our main work will take place.</p>
<p>Next, you'll need to configure PostCSS, which doesn't have an automated setup command like TailwindCSS. So you'll create the configuration file manually. Navigate to the project's root folder and create a file named <code>postcss.config.js</code>.</p>
<p>After creating the <code>postcss.config.js</code> file, simply copy and paste the provided code snippet into the file.</p>
<pre><code class="lang-js"><span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> {
  <span class="hljs-attr">plugins</span>: {
    <span class="hljs-attr">tailwindcss</span>: {},
    <span class="hljs-attr">autoprefixer</span>: {},
  },
};
</code></pre>
<p>Next, configure your <code>style.css</code> file to utilize Tailwind CSS defaults. This saves you from the tedious task of setting up CSS defaults manually. </p>
<p>Open the <code>style.css</code> file in your code editor, delete its contents, and then paste the following code snippet into the file:</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>
<h3 id="heading-delete-unneccasary-files-and-code">Delete unneccasary files and code</h3>
<p>The files generated by Vite primarily serve as guides for adding your own files and using the bundler effectively. So you can delete most of them since they are unnecessary for this project.</p>
<p>Below are the files to be removed from the project:</p>
<ol>
<li><code>counter.js</code></li>
<li><code>javascript.svg</code></li>
</ol>
<p>Once you've done that, you can move on to the next step in this section, which involves removing unnecessary code.</p>
<p>Open the <code>main.js</code> file located at the root of the project, and delete all the code within it.</p>
<p>Then, navigate to the <code>index.html</code> file and delete all of its current content. Afterwards, copy and paste the below code snippet into the file:</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">link</span> <span class="hljs-attr">rel</span>=<span class="hljs-string">"icon"</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"image/svg+xml"</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"/vite.svg"</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">title</span>&gt;</span>HTML5 Custom Video Player<span class="hljs-tag">&lt;/<span class="hljs-name">title</span>&gt;</span>
  <span class="hljs-tag">&lt;/<span class="hljs-name">head</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">body</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">h1</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"text-3xl font-bold underline text-red-800"</span>&gt;</span>Hello world!<span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>
    <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">"/main.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>
<span class="hljs-tag">&lt;/<span class="hljs-name">html</span>&gt;</span>
</code></pre>
<p>And with that, you're finished with this part! Your development environment is now set up, ready for you to begin building your custom HTML5 video player</p>
<p>To confirm that your environment is set up properly, check the following:</p>
<ol>
<li>The project files and folders should resemble the following structure:</li>
</ol>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/02/image-108.png" alt="Image" width="600" height="400" loading="lazy">
<em>Project setup completed: Visual Studio Code displaying project structure.</em></p>
<ol start="2">
<li>Open your terminal and run the following command:</li>
</ol>
<pre><code class="lang-bash">yarn dev
</code></pre>
<p>This will create a development server where your webpage will be hosted. Open the URL provided by Vite.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/02/image-109.png" alt="Image" width="600" height="400" loading="lazy">
<em>Launching Vite development server with 'yarn dev' command.</em></p>
<p>Upon opening the link <code>http://localhost:5173/</code>, you should see this:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/02/image-110.png" alt="Image" width="600" height="400" loading="lazy">
<em>The initial user interface displayed after executing 'yarn dev' command.</em></p>
<p>Congratulations! You have successfully completed this section on setting up your development environment, which will let us work effectively as we build our custom HTML5 video player.</p>
<p><strong>Troubleshooting:</strong> If you find that your setup isn't working as expected, don't worry. Simply delete the project folder and repeat the process. You may have missed a step or some tools might not have installed correctly. Also, double-check your Tailwind CSS and PostCSS configuration files to ensure they contain the correct code as shown above.</p>
<h2 id="heading-how-to-build-a-customized-ui-using-tailwind-css">How to Build a Customized UI using Tailwind CSS</h2>
<p>This section covers all the styling required to construct the UI of the custom HTML5 video player. We'll take a step-by-step walkthrough of the process.</p>
<p>First, copy and paste the following link tag into the head of your HTML, above the link to the stylesheet:</p>
<pre><code class="lang-css">&lt;<span class="hljs-selector-tag">link</span>
  <span class="hljs-selector-tag">href</span>="<span class="hljs-selector-tag">https</span>://<span class="hljs-selector-tag">fonts</span><span class="hljs-selector-class">.googleapis</span><span class="hljs-selector-class">.com</span>/<span class="hljs-selector-tag">icon</span>?<span class="hljs-selector-tag">family</span>=<span class="hljs-selector-tag">Material</span>+<span class="hljs-selector-tag">Icons</span>"
  <span class="hljs-selector-tag">rel</span>="<span class="hljs-selector-tag">stylesheet</span>"
/&gt;
</code></pre>
<p>This allows us to use <a target="_blank" href="https://materializecss.com/icons.html">Materialize CSS icons</a>, which are essential for styling our buttons in the UI. </p>
<p>Next, let's focus on styling the video element in our markup. Simply replace the <code>body</code> element with the provided code snippet below:</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">body</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"bg-indigo-950 p-10"</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">div</span>
    <span class="hljs-attr">id</span>=<span class="hljs-string">"container"</span>
    <span class="hljs-attr">class</span>=<span class="hljs-string">"w-4/5 h-4/5 mx-auto rounded-lg overflow-hidden relative group"</span>
  &gt;</span>
    <span class="hljs-comment">&lt;!-- VIDEO --&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">figure</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">video</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"w-full"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">source</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"/your-video.mp4"</span> /&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">video</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">figure</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">script</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"module"</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"/main.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 provided code snippet includes the markup and styling for the video element, as well as an outer div acting as a container for the entire video player UI. The video element is nested within a figure element.</p>
<p>For the <code>source</code> element, specify the path to the video you wish to play. You can find videos online, download them, and add them to the "public" directory within the project folder. Then, link the <code>src</code> attribute of the <code>source</code> element to the video file. You can find free downloadable videos <a target="_blank" href="https://www.pexels.com/search/videos/online/">here</a>.</p>
<p>Next, let's style the controls using the <a target="_blank" href="https://materializecss.com/icons.html">Materialize CSS Icons</a> you linked in your HTML. Place the following code snippet below the <code>figure</code> element inside the body element.</p>
<pre><code class="lang-html"><span class="hljs-comment">&lt;!-- CONTROLS --&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">div</span>
  <span class="hljs-attr">id</span>=<span class="hljs-string">"controls"</span>
  <span class="hljs-attr">class</span>=<span class="hljs-string">"opacity-0 p-5 absolute bottom-0 left-0 w-full transition-opacity duration-300 ease-linear group-hover:opacity-100"</span>
&gt;</span>
  <span class="hljs-comment">&lt;!-- PROGRESS BAR --&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"progress-bar"</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"h-1 w-full bg-white cursor-pointer mb-4"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">div</span>
      <span class="hljs-attr">id</span>=<span class="hljs-string">"progress-indicator"</span>
      <span class="hljs-attr">class</span>=<span class="hljs-string">"h-full w-9 bg-indigo-800 transition-all duration-500 ease-in-out"</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">class</span>=<span class="hljs-string">"flex items-center justify-between"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"flex items-center justify-between"</span>&gt;</span>
      <span class="hljs-comment">&lt;!-- REWIND BUTTON --&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">button</span>
        <span class="hljs-attr">id</span>=<span class="hljs-string">"rewind"</span>
        <span class="hljs-attr">class</span>=<span class="hljs-string">"transition-all duration-100 ease-linear hover:scale-125"</span>
      &gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">i</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"material-icons text-white text-3xl w-12"</span>&gt;</span>replay_10 <span class="hljs-tag">&lt;/<span class="hljs-name">i</span>&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>

      <span class="hljs-comment">&lt;!-- PLAY BUTTON --&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">button</span>
        <span class="hljs-attr">id</span>=<span class="hljs-string">"play-pause"</span>
        <span class="hljs-attr">class</span>=<span class="hljs-string">"transition-all duration-100 ease-linear hover:scale-125"</span>
      &gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">i</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"material-icons text-white text-5xl inline-block w-12"</span>
          &gt;</span>play_arrow<span class="hljs-tag">&lt;/<span class="hljs-name">i</span>
        &gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>

      <span class="hljs-comment">&lt;!-- FAST FORWARD BUTTON --&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">button</span>
        <span class="hljs-attr">id</span>=<span class="hljs-string">"fast-forward"</span>
        <span class="hljs-attr">class</span>=<span class="hljs-string">"transition-all duration-100 ease-linear hover:scale-125"</span>
      &gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">i</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"material-icons text-white text-3xl w-12"</span>&gt;</span>forward_10 <span class="hljs-tag">&lt;/<span class="hljs-name">i</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">div</span>&gt;</span>
      <span class="hljs-comment">&lt;!-- VOLUME BUTTON --&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">button</span>
        <span class="hljs-attr">id</span>=<span class="hljs-string">"volume"</span>
        <span class="hljs-attr">class</span>=<span class="hljs-string">"transition-all duration-100 ease-linear hover:scale-125"</span>
      &gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">i</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"material-icons text-white text-3xl"</span>&gt;</span>volume_up<span class="hljs-tag">&lt;/<span class="hljs-name">i</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">div</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
</code></pre>
<p>This code segment defines the layout and behavior of the controls for a video player. It begins by setting up a container div (<code>&lt;div id="controls"&gt;</code>) that holds all the control elements. The container is initially invisible (<code>opacity-0</code>) and becomes visible with a smooth transition (<code>transition-opacity duration-300 ease-linear</code>) when the user hovers over it (<code>group-hover:opacity-100</code>).</p>
<p>Within the container, there's a progress bar (<code>&lt;div id="progress-bar"&gt;</code>) for tracking the video's progress. It consists of a white background bar (<code>bg-white</code>) with a movable indicator (<code>&lt;div id="progress-indicator"&gt;</code>) colored in indigo (<code>bg-indigo-800</code>). The progress bar is responsive and allows users to seek to different parts of the video.</p>
<p>Below the progress bar are control buttons for various functions. The rewind, play/pause, and fast forward buttons are grouped together within a flex container (<code>&lt;div class="flex items-center justify-between"&gt;</code>). Each button (<code>&lt;button&gt;</code>) is styled to enlarge slightly (<code>hover:scale-125</code>) when hovered over.</p>
<ul>
<li>The rewind button (<code>&lt;button id="rewind"&gt;</code>) contains an icon (<code>&lt;i class="material-icons text-white text-3xl w-12"&gt;replay_10&lt;/i&gt;</code>) indicating a ten-second rewind.</li>
<li>The play/pause button (<code>&lt;button id="play-pause"&gt;</code>) contains an icon (<code>&lt;i class="material-icons text-white text-5xl w-12"&gt;play_arrow&lt;/i&gt;</code>) toggling between play and pause states.</li>
<li>The fast forward button (<code>&lt;button id="fast-forward"&gt;</code>) contains an icon (<code>&lt;i class="material-icons text-white text-3xl w-12"&gt;forward_10&lt;/i&gt;</code>) indicating a ten-second fast forward.</li>
</ul>
<p>Separately, there's a volume button (<code>&lt;button id="volume"&gt;</code>) located to the right of the control buttons. It contains a volume icon (<code>&lt;i class="material-icons text-white text-3xl w-12"&gt;volume_up&lt;/i&gt;</code>).</p>
<p>Overall, this code segment combines HTML and Tailwind CSS classes to create a functional and visually appealing set of controls for a video player.</p>
<p>The final puzzle is disabling the default browser feature, and we wouldn't want our custom HTML5 video player to clash with or be overridden by the default styling provided by browsers.</p>
<p>Copy and paste the code snippet below into your <code>style.css</code> file, directly below the Tailwind CSS directives:</p>
<pre><code class="lang-css"><span class="hljs-keyword">@layer</span> base {
  <span class="hljs-selector-tag">video</span><span class="hljs-selector-pseudo">::-webkit-media-controls</span> {
    <span class="hljs-attribute">display</span>: none;
  }

  <span class="hljs-selector-tag">video</span><span class="hljs-selector-pseudo">::-webkit-media-controls-play-button</span> {
    <span class="hljs-attribute">display</span>: none;
  }

  <span class="hljs-selector-tag">video</span><span class="hljs-selector-pseudo">::-webkit-media-controls-volume-slider</span> {
    <span class="hljs-attribute">display</span>: none;
  }

  <span class="hljs-selector-tag">video</span><span class="hljs-selector-pseudo">::-webkit-media-controls-mute-button</span> {
    <span class="hljs-attribute">display</span>: none;
  }

  <span class="hljs-selector-tag">video</span><span class="hljs-selector-pseudo">::-webkit-media-controls-timeline</span> {
    <span class="hljs-attribute">display</span>: none;
  }

  <span class="hljs-selector-tag">video</span><span class="hljs-selector-pseudo">::-webkit-media-controls-current-time-display</span> {
    <span class="hljs-attribute">display</span>: none;
  }
}
</code></pre>
<p>This piece of code is used to customize the appearance and behavior of the default media controls provided by the WebKit browser engine (commonly used in browsers like Safari and some versions of Google Chrome) for the <code>&lt;video&gt;</code> element.</p>
<p>Each CSS rule within the <code>@layer base</code> block targets specific parts of the default media controls and hides them from view by setting their <code>display</code> property to <code>none</code>. Here's a breakdown of each rule:</p>
<ol>
<li><code>video::-webkit-media-controls</code>: This rule targets the entire set of media controls for the <code>&lt;video&gt;</code> element and hides them completely. By hiding the controls, you can implement your own custom controls using JavaScript and CSS, providing a more tailored and consistent user experience across different browsers.</li>
<li><code>video::-webkit-media-controls-play-button</code>: This rule targets the play button within the default media controls and hides it. We might want to hide the play button if we're using a custom play button design or handling playback control programmatically.</li>
<li><code>video::-webkit-media-controls-volume-slider</code>: This rule targets the volume slider within the default media controls and hides it. Similar to hiding the play button, you might choose to hide the volume slider if you're implementing your own volume control UI.</li>
<li><code>video::-webkit-media-controls-mute-button</code>: This rule targets the mute button within the default media controls and hides it. If you have a custom mute/unmute button or want to manage audio muting programmatically, you can hide the default mute button.</li>
<li><code>video::-webkit-media-controls-timeline</code>: This rule targets the timeline (progress bar) within the default media controls and hides it. By hiding the timeline, you can implement your own progress bar with custom styling and additional functionality.</li>
<li><code>video::-webkit-media-controls-current-time-display</code>: This rule targets the current time display within the default media controls and hides it. If you're implementing a custom UI for displaying the current playback time, you can hide the default display.</li>
</ol>
<p>Overall, this code allows for complete customization of the default media controls provided by WebKit browsers, letting you create a unique and tailored user experience for video playback on your websites.</p>
<p>Check your localhost URL to see a customized UI displayed like this:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/02/image-114.png" alt="Image" width="600" height="400" loading="lazy">
<em>Custom video player UI without mouse hover, controls hidden.</em></p>
<p>However, upon hovering, the controls will fade in and the UI will be displayed like this:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/02/image-113.png" alt="Image" width="600" height="400" loading="lazy">
<em>Custom video player UI with visible controls upon mouse hover.</em></p>
<p>And there you have it! You've successfully constructed a customized HTML5 video player. Now, it's time to breathe life into it by using JavaScript to develop the controls and functionality, which we'll tackle in the upcoming sections.</p>
<h2 id="heading-how-to-implement-the-play-and-pause-functionality">How to Implement the Play and Pause Functionality</h2>
<p>To implement the play and pause feature on the HTML5 custom video player, you'll start by selecting the play and pause buttons using their respective IDs from the markup. You can also select the video element. Then you'll programmatically control the playback using the Video API provided by JavaScript in the browser. Let's get started.</p>
<pre><code class="lang-js"><span class="hljs-meta">"use strict"</span>;

<span class="hljs-keyword">const</span> playNpauseBtn = <span class="hljs-built_in">document</span>.querySelector(<span class="hljs-string">"#play-pause"</span>);
<span class="hljs-keyword">const</span> video = <span class="hljs-built_in">document</span>.querySelector(<span class="hljs-string">"video"</span>);
</code></pre>
<p>From the code snippet above:</p>
<ul>
<li><code>"use strict";</code> ensures JavaScript runs in strict mode, catching common coding mistakes.</li>
<li><code>const playNpauseBtn = document.querySelector("#play-pause");</code> selects the play/pause button from the HTML using its ID.</li>
<li><code>const video = document.querySelector("video");</code> selects the video element from the HTML.</li>
</ul>
<p>Next, let's create two functions:</p>
<ol>
<li><code>playNpauseFn</code>: This function will handle playing and pausing the video.</li>
<li><code>updatePlayNPauseIcon</code>: This function will update the play and pause icons based on the video's current state. For example, if the video is playing, it will show the pause icon, and vice versa.</li>
</ol>
<p>Now, let's examine how this will function in the following code snippet.</p>
<pre><code class="lang-js"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">playNpauseFn</span>(<span class="hljs-params"></span>) </span>{
  video.paused ? video.play() : video.pause();
}

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">updatePlayNPauseIcon</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> icon = playNpauseBtn.querySelector(<span class="hljs-string">"i"</span>);
  icon.textContent = <span class="hljs-string">""</span>;

  icon.textContent = video.paused ? <span class="hljs-string">"play_arrow"</span> : <span class="hljs-string">"paused"</span>;
}
</code></pre>
<p>Let's understand what's happening. Beginning with the <code>playNpauseFn</code> function, when it's called, it checks the current state of the video using the <code>paused</code> method available in the Video API. If the video is paused, it plays the video. Otherwise, it pauses the video. This is accomplished using the ternary operator in JavaScript.</p>
<p>Alternatively, you can rewrite this using the if/else statement, as shown below:</p>
<pre><code class="lang-js"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">playNpauseFn</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">if</span> (video.paused) {
    video.play();
  } <span class="hljs-keyword">else</span> {
    video.paused();
  }
}
</code></pre>
<p>The code sample above accomplishes the same task as the previous version – either one will work.</p>
<p>Now, let's move on to the second function, <code>updatePlayNPauseIcon</code>. This function updates the play and pause icons based on the current state of the video. Let's review how it's implemented.</p>
<p>Check out the icon styling below:</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">button</span>
  <span class="hljs-attr">id</span>=<span class="hljs-string">"play-pause"</span>
  <span class="hljs-attr">class</span>=<span class="hljs-string">"transition-all duration-100 ease-linear hover:scale-125"</span>
&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">i</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"material-icons text-white text-5xl inline-block w-12"</span>&gt;</span>play_arrow<span class="hljs-tag">&lt;/<span class="hljs-name">i</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
</code></pre>
<p>This code makes a button with the ID "play-pause" that holds an icon specified by the <code>&lt;i&gt;</code> tag. Materialize CSS uses the text "play_arrow" inside the <code>&lt;i&gt;</code> tag to show the matching icon. If you change the text inside <code>&lt;i&gt;</code>, Materialize CSS updates the icon accordingly.</p>
<p>Now, let's focus on the function responsible for updating the icon. Take a look at it below in isolation:</p>
<pre><code class="lang-js"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">updatePlayNPauseIcon</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> icon = playNpauseBtn.querySelector(<span class="hljs-string">"i"</span>);
  icon.textContent = <span class="hljs-string">""</span>;

  icon.textContent = video.paused ? <span class="hljs-string">"play_arrow"</span> : <span class="hljs-string">"paused"</span>;
}
</code></pre>
<p>This function, <code>updatePlayNPauseIcon()</code>, is responsible for updating the play/pause icon based on the current state of the video.</p>
<ol>
<li>It first selects the icon element inside the play/pause button.</li>
<li>Then, it clears any existing text content within the icon.</li>
<li>Finally, it sets the text content of the icon to "play_arrow" if the video is paused, or "paused" if the video is currently playing. This dynamically changes the icon displayed on the button to reflect the current playback state.</li>
</ol>
<p><strong>Note:</strong> The way you update icons programmatically can vary based on the icon service and its API. This particular implementation is specific to Materialize CSS icons.</p>
<p>Next, let's connect these functions to the events that trigger them. Let's see how that works below:</p>
<pre><code class="lang-js">video.addEventListener(<span class="hljs-string">"play"</span>, updatePlayNPauseIcon);
video.addEventListener(<span class="hljs-string">'click'</span>, playNpauseFn)
video.addEventListener(<span class="hljs-string">"pause"</span>, updatePlayNPauseIcon);
playNpauseBtn.addEventListener(<span class="hljs-string">"click"</span>, playNpauseFn);
</code></pre>
<p>In this code:</p>
<ul>
<li><code>video.addEventListener("play", updatePlayNPauseIcon);</code>: This line adds an event listener to the video element, specifically listening for the "play" event. When the video starts playing, it triggers the <code>updatePlayNPauseIcon</code> function, updating the play/pause icon accordingly.</li>
<li><code>video.addEventListener('click', playNpauseFn)</code>: This line adds an event listener to the video element for the "click" event. When the video is clicked, it triggers the <code>playNpauseFn</code> function, which plays or pauses the video.</li>
<li><code>video.addEventListener("pause", updatePlayNPauseIcon);</code>: This line adds an event listener to the video element, listening for the "pause" event. When the video is paused, it triggers the <code>updatePlayNPauseIcon</code> function to update the play/pause icon.</li>
<li><code>playNpauseBtn.addEventListener("click", playNpauseFn);</code>: This line adds an event listener to the play/pause button element. When the button is clicked, it triggers the <code>playNpauseFn</code> function, which plays or pauses the video.</li>
</ul>
<p>We have four event listeners on the two selected elements. Let's break down what's happening:</p>
<ul>
<li>The video element listens for the "play" event. When the video starts playing, it triggers <code>updatePlayNPauseIcon</code>, updating the icon based on the video's current state.</li>
<li>The video element also listens for a click event. When clicked, it triggers <code>playNpauseFn</code>, which toggles between playing and pausing the video.</li>
<li>Also, the video element listens for the "pause" event. When the video is paused, it triggers <code>playNpauseFn</code>, toggling the video's playback state.</li>
<li>The play/pause button element also listens for a click event. When clicked, it triggers <code>playNpauseFn</code>, toggling between playing and pausing the video.</li>
</ul>
<p>That concludes this section. You can now try the play and pause functionality. The video should pause and play effectively, with the icons updating correctly.</p>
<p>At the moment your custom video should player should be doing this:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/02/play-pause.gif" alt="Image" width="600" height="400" loading="lazy">
<em>Testing out the play and pause functionality</em></p>
<p>In the next section, we'll be implementing the rewind and fast forward feature.</p>
<h2 id="heading-how-to-implement-the-rewind-and-fast-forward-functionality">How to Implement the Rewind and Fast Forward Functionality</h2>
<p>Now that we've implemented the play and pause functionality, the next features to add are rewind and fast forward. These common features allow users to skip forward or backward in the video by a set number of seconds. </p>
<p>First, let's begin by selecting the corresponding buttons from the HTML document using their IDs and storing them in variables:</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> rewindBtn = <span class="hljs-built_in">document</span>.querySelector(<span class="hljs-string">"#rewind"</span>);
<span class="hljs-keyword">const</span> fastForwardBtn = <span class="hljs-built_in">document</span>.querySelector(<span class="hljs-string">"#fast-forward"</span>);
</code></pre>
<p>Once that's completed, you need to construct the function responsible for implementing the rewind and fast forward functionality. Below is the code snippet:</p>
<pre><code class="lang-js"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">rewindNforwardFn</span>(<span class="hljs-params">type</span>) </span>{
  video.currentTime += type === <span class="hljs-string">"rewind"</span> ? <span class="hljs-number">-10</span> : <span class="hljs-number">10</span>;
}
</code></pre>
<p>This function, called <code>rewindNforward</code>, is responsible for rewinding or fast-forwarding the video. Here's how it works:</p>
<ul>
<li>It takes a parameter called <code>type</code>, which indicates whether you want to rewind or fast forward.</li>
<li>If <code>type</code> is "rewind", it subtracts 10 seconds from the current playback time of the video (<code>video.currentTime</code>).</li>
<li>If <code>type</code> is not "rewind" (indicating that you want to fast forward), it adds 10 seconds to the current playback time of the video. This allows users to navigate through the video either backward or forward by 10-second intervals, depending on the value of <code>type</code>.</li>
</ul>
<p>Next, you need to connect the event listeners on the buttons to trigger the <code>rewindNforward</code> function.</p>
<pre><code class="lang-js">rewindBtn.addEventListener(<span class="hljs-string">"click"</span>, <span class="hljs-function">() =&gt;</span> rewindNforwardFn(<span class="hljs-string">"rewind"</span>));
fastForwardBtn.addEventListener(<span class="hljs-string">"click"</span>, <span class="hljs-function">() =&gt;</span> rewindNforwardFn(<span class="hljs-string">"forward"</span>));
</code></pre>
<p>This code adds event listeners to the rewind and fast forward buttons. When the rewind button is clicked, it triggers the <code>rewindNforward</code> function with the argument "rewind", indicating that you want to rewind the video. </p>
<p>Similarly, when the fast forward button is clicked, it triggers the <code>rewindNforward</code> function with the argument "forward", indicating that you want to fast forward the video.</p>
<p>Feel free to test it out and observe how it functions on the user interface (UI).</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/02/rewind-1.gif" alt="Image" width="600" height="400" loading="lazy">
<em>Testing the rewind and fast forward functionality</em></p>
<h2 id="heading-how-to-implement-the-mute-and-unmute-functionality">How to Implement the Mute and Unmute Functionality</h2>
<p>To add the mute and unmute functionality, you'll follow the same process as you did for the previous functionalities.</p>
<p>You'll begin by selecting the volume button from the HTML document using the <code>querySelector</code> method:</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> volumeBtn = <span class="hljs-built_in">document</span>.querySelector(<span class="hljs-string">"#volume"</span>);
</code></pre>
<p>Then, create the functions responsible for muting and unmuting the video, and update the icon accordingly when either of these events occurs.</p>
<pre><code class="lang-js"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">muteNunmuteFn</span>(<span class="hljs-params"></span>) </span>{
  video.muted = video.muted ? <span class="hljs-literal">false</span> : <span class="hljs-literal">true</span>;
}

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">updateVolumeIcon</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> icon = volumeBtn.querySelector(<span class="hljs-string">"i"</span>);
  icon.textContent = <span class="hljs-string">""</span>;
  icon.textContent = video.muted ? <span class="hljs-string">"volume_off"</span> : <span class="hljs-string">"volume_up"</span>;
}
</code></pre>
<p>This code comprises two functions:</p>
<ol>
<li><code>muteNunmuteFn()</code>: This function toggles the video's mute state. If the video is currently muted, it unmutes it. Otherwise, it mutes the video.</li>
<li><code>updateVolumeIcon()</code>: This function updates the volume icon displayed on the volume button. It clears any existing icon content, then sets the icon text to "volume_off" if the video is muted, and "volume_up" if the video is not muted.</li>
</ol>
<p>The final step is to connect the functions with event listeners so that they are executed when the event is triggered. Below are the code snippets for this:</p>
<pre><code class="lang-js">video.addEventListener(<span class="hljs-string">"volumechange"</span>, updateVolumeIcon);
volumeBtn.addEventListener(<span class="hljs-string">"click"</span>, muteNunmuteFn);
</code></pre>
<p>This code sets up two things:</p>
<ol>
<li>It adds an event listener to the video element, listening for the "volumechange" event. When this event occurs (that is, when the volume is changed), it triggers the <code>updateVolumeIcon</code> function to update the volume icon accordingly.</li>
<li>It adds an event listener to the volume button. When the volume button is clicked, it triggers the <code>muteNunmuteFn</code> function, toggling between muting and unmuting the video.</li>
</ol>
<p>Similar to the <code>play</code> and <code>pause</code> events, the video also has a <code>volumechange</code> event triggered when the volume or mute status changes. You set up the video to listen for this event, so when it occurs, the event listener runs the function to update the volume icon accordingly.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/02/volume.gif" alt="Image" width="600" height="400" loading="lazy">
<em>Testing out the mute and unmute functionality</em></p>
<h2 id="heading-how-to-update-the-progress-bar-relative-to-the-video-time">How to Update the Progress Bar Relative to the Video Time</h2>
<p>In this section, you'll see how to update the progress bar as the video plays, allowing users to track their progress through the video.</p>
<p>The progress bar currently doesn't move as the video plays and the time changes. We're going to fix that</p>
<p>To start, you'll remove the fixed width styling for the progress bar. Originally added for styling purposes, it's no longer needed as you'll dynamically adjust the width using JavaScript. Update the class from <code>w-9</code> to <code>w-0</code> in the div element with the id "progress-indicator".</p>
<pre><code class="lang-html"><span class="hljs-comment">&lt;!-- PROGRESS BAR --&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"progress-bar"</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"h-1 w-full bg-white cursor-pointer mb-4"</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">div</span>
    <span class="hljs-attr">id</span>=<span class="hljs-string">"progress-indicator"</span>
    <span class="hljs-attr">class</span>=<span class="hljs-string">"h-full w-0 bg-indigo-800 transition-all duration-500 ease-in-out"</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>Moving on to implementing the progress bar update, the first step is to select the progress bar indicator element. This element's width will increase as the video time progresses. Below is the code snippet to achieve this:</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> progressIndicator = <span class="hljs-built_in">document</span>.querySelector(<span class="hljs-string">"#progress-indicator"</span>);
</code></pre>
<p>Once the progress indicator is selected, your next task is to implement the function responsible for updating it.</p>
<pre><code class="lang-js"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">updateProgress</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> progressPercentage = (video.currentTime / video.duration) * <span class="hljs-number">100</span>;

  progressIndicator.style.width = <span class="hljs-string">`<span class="hljs-subst">${progressPercentage}</span>%`</span>;
}
</code></pre>
<p>In the code snippet above, the function called <code>updateProgress</code> calculates the percentage of video progress by dividing the current time of the video by its total duration and then multiplying by 100. This percentage is used to set the width of the progress indicator element, visually representing how much of the video has been watched.</p>
<p>Let's break down the function. In the first line of code, you calculate the percentage of the video's current time compared to its total duration. You do this by dividing the current time by the total duration of the video. For example, if a video is 30 seconds long and the current time is 3 seconds, 3 divided by 30 equals 0.1. </p>
<p>You then multiply this decimal by 100 to get the percentage. So, 0.1 multiplied by 100 equals 10. This means you are 10% into the 30-second video. </p>
<p>Finally, you use this percentage to update the width of the progress indicator accordingly.</p>
<p>Next, let's add an event listener that triggers this function. See the code snippet below:</p>
<pre><code class="lang-js">video.addEventListener(<span class="hljs-string">'timeupdate'</span>, updateProgress);
</code></pre>
<p>Similar to other events in the Video API, there's another one called <code>timeupdate</code>. This event is triggered as the <code>currentTime</code> of the video changes. So, as the time updates, the <code>updateProgress</code> function is automatically executed each time the event is fired, causing the progress indicator to update accordingly.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/02/progress.gif" alt="Image" width="600" height="400" loading="lazy">
<em>Testing out the time progress functionality</em></p>
<h2 id="heading-how-to-implement-the-seeking-functionality">How to Implement the Seeking Functionality</h2>
<p>The seeking functionality is a vital aspect of video players. While rewind and fast forward are efficient for small skips, users often want to make larger jumps to specific parts of the video. Clicking rewind or fast forward, which only moves in fixed increments, can be frustrating for users. So the seeking functionality proves invaluable in such scenarios.</p>
<p>Let's begin by selecting the progress bar element from the Document Object Model (DOM).</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> progessBar = <span class="hljs-built_in">document</span>.querySelector(<span class="hljs-string">"#progress-bar"</span>);
</code></pre>
<p>Having obtained the progress bar from the DOM using its ID, your next step is to construct the seeking function. You can find the implementation in the following code snippet:</p>
<pre><code class="lang-js"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">seekingFn</span>(<span class="hljs-params">e</span>) </span>{
  <span class="hljs-keyword">const</span> updatedTime = (e.offsetX / progessBar.offsetWidth) * video.duration;

  video.currentTime = updatedTime;
}
</code></pre>
<p>Let's breakdown the function and understand what's going on.</p>
<p>The function, <code>seekingFn</code>, adjusts the current playback time of the video based on the position where the user clicks on the progress bar. It calculates the updated time by dividing the horizontal offset of the click relative to the progress bar width by the total width of the progress bar. Then it multiplies it by the total duration of the video. Finally, it sets the current time of the video to the calculated updated time.</p>
<p>Next, add the event listener:</p>
<pre><code class="lang-js"><span class="hljs-keyword">let</span> mouseIsDown = <span class="hljs-literal">false</span>;

progessBar.addEventListener(<span class="hljs-string">"mousedown"</span>, <span class="hljs-function">() =&gt;</span> (mouseIsDown = <span class="hljs-literal">true</span>));
progessBar.addEventListener(<span class="hljs-string">"mouseup"</span>, <span class="hljs-function">() =&gt;</span> (mouseIsDown = <span class="hljs-literal">false</span>));
progessBar.addEventListener(<span class="hljs-string">"click"</span>, seekingFn);
progessBar.addEventListener(<span class="hljs-string">"mousemove"</span>, <span class="hljs-function">(<span class="hljs-params">e</span>) =&gt;</span> mouseIsDown &amp;&amp; seekingFn);
</code></pre>
<p>In the code snippet above, the code handles mouse events on the progress bar for seeking functionality:</p>
<ul>
<li><code>mouseIsDown</code> is a variable that tracks whether the mouse button is pressed down.</li>
<li>When the mouse button is pressed down (<code>mousedown</code> event), <code>mouseIsDown</code> is set to true.</li>
<li>When the mouse button is released (<code>mouseup</code> event), <code>mouseIsDown</code> is set to false.</li>
<li>When the progress bar is clicked (<code>click</code> event), the <code>seekingFn</code> function is triggered to seek to the clicked position.</li>
<li>When the mouse moves over the progress bar (<code>mousemove</code> event), if <code>mouseIsDown</code> is true, meaning the mouse button is pressed, then the <code>seekingFn</code> function is triggered, allowing seeking while dragging the mouse.</li>
</ul>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/02/seeking.gif" alt="Image" width="600" height="400" loading="lazy">
<em>Testing the seeking functionality</em></p>
<h2 id="heading-how-to-add-keyboard-navigation-for-accesibility">How to Add Keyboard Navigation for Accesibility</h2>
<p>Our video player currently supports pointer devices like mice and light pens. But we aim to ensure accessibility for users who may not have or be able to use such devices. So we're striving to make our custom HTML5 video player usable without the need for a pointer device, utilizing keyboards instead.</p>
<h3 id="heading-using-the-space-bar-for-play-and-pause">Using the space bar for play and pause</h3>
<p>Let's start by improving the play and pause functionality. In most video players, it's common to use the space bar on the keyboard to toggle between playing and pausing a video. This is the first keyboard navigation feature we'll implement.</p>
<p>Below is a code snippet demonstrating how to achieve this:</p>
<pre><code class="lang-js"><span class="hljs-built_in">window</span>.addEventListener(<span class="hljs-string">"keyup"</span>, <span class="hljs-function">(<span class="hljs-params">e</span>) =&gt;</span> {
  <span class="hljs-keyword">if</span> (e.code === <span class="hljs-string">"Space"</span>) {
    playNpauseFn();
  }
});
</code></pre>
<p>This code listens for when a key on your keyboard is released, known as a "keyup" event. If the key released happens to be the space bar, it triggers the function that toggles between playing and pausing the video. You'll just be reusing the function you made earlier for this.</p>
<p>Here's a step-by-step explanation of the code:</p>
<ol>
<li><p><strong><code>window.addEventListener("keyup", (e) =&gt; { ... })</code>:</strong></p>
</li>
<li><p>You're adding an event listener to the <code>window</code> object.</p>
</li>
<li><p>This listener is triggered when a key is released (<code>keyup</code> event).</p>
</li>
<li><p><strong>  <code>(e) =&gt; { ... }</code>:</strong></p>
</li>
<li><p>This is an arrow function that gets executed when the <code>keyup</code> event occurs.</p>
</li>
<li><p>The <code>e</code> parameter represents the event object containing information about the event.</p>
</li>
<li><p><strong><code>if (e.code === "Space") { ... }</code>:</strong></p>
</li>
<li><p>This condition checks if the key that was released is the space bar.</p>
</li>
<li><p><code>e.code</code> provides the code of the key that triggered the event.</p>
</li>
<li><p><strong><code>playNpauseFn();</code>:</strong></p>
</li>
<li><p>If the released key is the space bar, this function is called.</p>
</li>
<li>The <code>playNpauseFn</code> function is responsible for toggling between playing and pausing the video.</li>
</ol>
<h3 id="heading-using-the-arrow-keys-to-rewind-and-fast-forward">Using the arrow keys to rewind and fast forward</h3>
<p>You can use the left arrow key to rewind and the right arrow key to fast forward a video, in addition to the space bar for playing and pausing.</p>
<p>Building upon the previous code snippet for play and pause functionality, you can incorporate the arrow keys for rewinding and fast forwarding the video.</p>
<pre><code class="lang-js"><span class="hljs-built_in">window</span>.addEventListener(<span class="hljs-string">"keyup"</span>, <span class="hljs-function">(<span class="hljs-params">e</span>) =&gt;</span> {
  <span class="hljs-keyword">if</span> (e.code === <span class="hljs-string">"Space"</span>) {
    playNpauseFn();
  } <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (e.code === <span class="hljs-string">"ArrowLeft"</span>) {
    rewindNforwardFn(<span class="hljs-string">"rewind"</span>);
  } <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (e.code === <span class="hljs-string">"ArrowRight"</span>) {
    rewindNforwardFn(<span class="hljs-string">"forward"</span>);
  } <span class="hljs-keyword">else</span> {
    <span class="hljs-keyword">return</span>;
  }
});
</code></pre>
<p>This code snippet sets up an event listener on the window object for the keyup event. When any key is released, the provided callback function is triggered with an event parameter. Inside the callback function, there are conditional statements to check which key was pressed:</p>
<ul>
<li>If the pressed key is the Space bar ("Space"), the <code>playNpauseFn</code> function is executed, toggling between play and pause of the video.</li>
<li>If the pressed key is the left arrow key ("ArrowLeft"), the <code>rewindNforwardFn</code> function is called with the argument "rewind", indicating the video should be rewound.</li>
<li>If the pressed key is the right arrow key ("ArrowRight"), the <code>rewindNforwardFn</code> function is called with the argument "forward", indicating the video should be fast forwarded.</li>
<li>If the pressed key isn't the space bar, left arrow, or right arrow, the function returns without performing any action.</li>
</ul>
<h3 id="heading-how-your-code-should-look-now">How your code should look now</h3>
<p>We've now finished building our custom HTML5 video player. Congratulations to you on learning this.</p>
<p>If you encountered any difficulties or missed any steps along the way, don't worry. You can find the code snippets for each major file below:</p>
<p><strong>index.html</strong></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">link</span> <span class="hljs-attr">rel</span>=<span class="hljs-string">"icon"</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"image/svg+xml"</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"/vite.svg"</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">href</span>=<span class="hljs-string">"https://fonts.googleapis.com/icon?family=Material+Icons"</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">"./style.css"</span> /&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">title</span>&gt;</span>HTML5 Custom Video Player<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> <span class="hljs-attr">class</span>=<span class="hljs-string">"bg-indigo-950 p-10"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">div</span>
      <span class="hljs-attr">id</span>=<span class="hljs-string">"container"</span>
      <span class="hljs-attr">class</span>=<span class="hljs-string">"w-4/5 h-4/5 mx-auto rounded-lg overflow-hidden relative group"</span>
    &gt;</span>
      <span class="hljs-comment">&lt;!-- VIDEO --&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">figure</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">video</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"w-full"</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">source</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"/oceans.mp4"</span> /&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">video</span>&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">figure</span>&gt;</span>

      <span class="hljs-comment">&lt;!-- CONTROLS --&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">div</span>
        <span class="hljs-attr">id</span>=<span class="hljs-string">"controls"</span>
        <span class="hljs-attr">class</span>=<span class="hljs-string">"opacity-0 p-5 absolute bottom-0 left-0 w-full transition-opacity duration-300 ease-linear group-hover:opacity-100"</span>
      &gt;</span>
        <span class="hljs-comment">&lt;!-- PROGRESS BAR --&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"progress-bar"</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"h-1 w-full bg-white cursor-pointer mb-4"</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">div</span>
            <span class="hljs-attr">id</span>=<span class="hljs-string">"progress-indicator"</span>
            <span class="hljs-attr">class</span>=<span class="hljs-string">"h-full w-0 bg-indigo-800 transition-all duration-500 ease-in-out"</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">class</span>=<span class="hljs-string">"flex items-center justify-between"</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"flex items-center justify-between"</span>&gt;</span>
            <span class="hljs-comment">&lt;!-- REWIND BUTTON --&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">button</span>
              <span class="hljs-attr">id</span>=<span class="hljs-string">"rewind"</span>
              <span class="hljs-attr">class</span>=<span class="hljs-string">"transition-all duration-100 ease-linear hover:scale-125"</span>
            &gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">i</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"material-icons text-white text-3xl w-12"</span>&gt;</span>replay_10 <span class="hljs-tag">&lt;/<span class="hljs-name">i</span>&gt;</span>
            <span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>

            <span class="hljs-comment">&lt;!-- PLAY BUTTON --&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">button</span>
              <span class="hljs-attr">id</span>=<span class="hljs-string">"play-pause"</span>
              <span class="hljs-attr">class</span>=<span class="hljs-string">"transition-all duration-100 ease-linear hover:scale-125"</span>
            &gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">i</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"material-icons text-white text-5xl inline-block w-12"</span>
                &gt;</span>play_arrow<span class="hljs-tag">&lt;/<span class="hljs-name">i</span>
              &gt;</span>
            <span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>

            <span class="hljs-comment">&lt;!-- FAST FORWARD BUTTON --&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">button</span>
              <span class="hljs-attr">id</span>=<span class="hljs-string">"fast-forward"</span>
              <span class="hljs-attr">class</span>=<span class="hljs-string">"transition-all duration-100 ease-linear hover:scale-125"</span>
            &gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">i</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"material-icons text-white text-3xl w-12"</span>&gt;</span>forward_10 <span class="hljs-tag">&lt;/<span class="hljs-name">i</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">div</span>&gt;</span>
            <span class="hljs-comment">&lt;!-- VOLUME BUTTON --&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">button</span>
              <span class="hljs-attr">id</span>=<span class="hljs-string">"volume"</span>
              <span class="hljs-attr">class</span>=<span class="hljs-string">"transition-all duration-100 ease-linear hover:scale-125"</span>
            &gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">i</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"material-icons text-white text-3xl"</span>&gt;</span>volume_up<span class="hljs-tag">&lt;/<span class="hljs-name">i</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">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">script</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"module"</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"/main.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>
<span class="hljs-tag">&lt;/<span class="hljs-name">html</span>&gt;</span>
</code></pre>
<p><strong>style.css</strong></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;

<span class="hljs-keyword">@layer</span> base {
  <span class="hljs-selector-tag">video</span><span class="hljs-selector-pseudo">::-webkit-media-controls</span> {
    <span class="hljs-attribute">display</span>: none;
  }

  <span class="hljs-selector-tag">video</span><span class="hljs-selector-pseudo">::-webkit-media-controls-play-button</span> {
    <span class="hljs-attribute">display</span>: none;
  }

  <span class="hljs-selector-tag">video</span><span class="hljs-selector-pseudo">::-webkit-media-controls-volume-slider</span> {
    <span class="hljs-attribute">display</span>: none;
  }

  <span class="hljs-selector-tag">video</span><span class="hljs-selector-pseudo">::-webkit-media-controls-mute-button</span> {
    <span class="hljs-attribute">display</span>: none;
  }

  <span class="hljs-selector-tag">video</span><span class="hljs-selector-pseudo">::-webkit-media-controls-timeline</span> {
    <span class="hljs-attribute">display</span>: none;
  }

  <span class="hljs-selector-tag">video</span><span class="hljs-selector-pseudo">::-webkit-media-controls-current-time-display</span> {
    <span class="hljs-attribute">display</span>: none;
  }
}
</code></pre>
<p><strong>main.js</strong></p>
<pre><code class="lang-js"><span class="hljs-meta">"use strict"</span>;

<span class="hljs-keyword">const</span> playNpauseBtn = <span class="hljs-built_in">document</span>.querySelector(<span class="hljs-string">"#play-pause"</span>);
<span class="hljs-keyword">const</span> video = <span class="hljs-built_in">document</span>.querySelector(<span class="hljs-string">"video"</span>);
<span class="hljs-keyword">const</span> rewindBtn = <span class="hljs-built_in">document</span>.querySelector(<span class="hljs-string">"#rewind"</span>);
<span class="hljs-keyword">const</span> fastForwardBtn = <span class="hljs-built_in">document</span>.querySelector(<span class="hljs-string">"#fast-forward"</span>);
<span class="hljs-keyword">const</span> volumeBtn = <span class="hljs-built_in">document</span>.querySelector(<span class="hljs-string">"#volume"</span>);
<span class="hljs-keyword">const</span> progressIndicator = <span class="hljs-built_in">document</span>.querySelector(<span class="hljs-string">"#progress-indicator"</span>);
<span class="hljs-keyword">const</span> progessBar = <span class="hljs-built_in">document</span>.querySelector(<span class="hljs-string">"#progress-bar"</span>);

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">playNpauseFn</span>(<span class="hljs-params"></span>) </span>{
  video.paused ? video.play() : video.pause();
}

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">updatePlayNPauseIcon</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> icon = playNpauseBtn.querySelector(<span class="hljs-string">"i"</span>);
  icon.textContent = <span class="hljs-string">""</span>;

  icon.textContent = video.paused ? <span class="hljs-string">"play_arrow"</span> : <span class="hljs-string">"paused"</span>;
}

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">rewindNforwardFn</span>(<span class="hljs-params">type</span>) </span>{
  video.currentTime += type === <span class="hljs-string">"rewind"</span> ? <span class="hljs-number">-10</span> : <span class="hljs-number">10</span>;
}

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">muteNunmuteFn</span>(<span class="hljs-params"></span>) </span>{
  video.muted = video.muted ? <span class="hljs-literal">false</span> : <span class="hljs-literal">true</span>;
}

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">updateVolumeIcon</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> icon = volumeBtn.querySelector(<span class="hljs-string">"i"</span>);
  icon.textContent = <span class="hljs-string">""</span>;
  icon.textContent = video.muted ? <span class="hljs-string">"volume_off"</span> : <span class="hljs-string">"volume_up"</span>;
}

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">updateProgress</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> progressPercentage = (video.currentTime / video.duration) * <span class="hljs-number">100</span>;

  progressIndicator.style.width = <span class="hljs-string">`<span class="hljs-subst">${progressPercentage}</span>%`</span>;
}

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">seekingFn</span>(<span class="hljs-params">e</span>) </span>{
  <span class="hljs-keyword">const</span> updatedTime = (e.offsetX / progessBar.offsetWidth) * video.duration;

  video.currentTime = updatedTime;
}

<span class="hljs-comment">// PLAY AND PAUSE FUNCTIONALITY</span>
video.addEventListener(<span class="hljs-string">"play"</span>, updatePlayNPauseIcon);
video.addEventListener(<span class="hljs-string">"click"</span>, playNpauseFn);
video.addEventListener(<span class="hljs-string">"pause"</span>, updatePlayNPauseIcon);
playNpauseBtn.addEventListener(<span class="hljs-string">"click"</span>, playNpauseFn);

<span class="hljs-comment">// REWIND AND FAST FORWARD</span>
rewindBtn.addEventListener(<span class="hljs-string">"click"</span>, <span class="hljs-function">() =&gt;</span> rewindNforwardFn(<span class="hljs-string">"rewind"</span>));
fastForwardBtn.addEventListener(<span class="hljs-string">"click"</span>, <span class="hljs-function">() =&gt;</span> rewindNforwardFn(<span class="hljs-string">"forward"</span>));

<span class="hljs-comment">// MUTE AND UNMUTE</span>
video.addEventListener(<span class="hljs-string">"volumechange"</span>, updateVolumeIcon);
volumeBtn.addEventListener(<span class="hljs-string">"click"</span>, muteNunmuteFn);

<span class="hljs-comment">// PROGRESS</span>
video.addEventListener(<span class="hljs-string">"timeupdate"</span>, updateProgress);

<span class="hljs-comment">// SEEKING</span>
<span class="hljs-keyword">let</span> mouseIsDown = <span class="hljs-literal">false</span>;

progessBar.addEventListener(<span class="hljs-string">"mousedown"</span>, <span class="hljs-function">() =&gt;</span> (mouseIsDown = <span class="hljs-literal">true</span>));
progessBar.addEventListener(<span class="hljs-string">"mouseup"</span>, <span class="hljs-function">() =&gt;</span> (mouseIsDown = <span class="hljs-literal">false</span>));
progessBar.addEventListener(<span class="hljs-string">"click"</span>, seekingFn);
progessBar.addEventListener(<span class="hljs-string">"mousemove"</span>, <span class="hljs-function">(<span class="hljs-params">e</span>) =&gt;</span> mouseIsDown &amp;&amp; seekingFn);

<span class="hljs-comment">// KEYBOARD NAVIGATIONS</span>
<span class="hljs-built_in">window</span>.addEventListener(<span class="hljs-string">"keyup"</span>, <span class="hljs-function">(<span class="hljs-params">e</span>) =&gt;</span> {
  <span class="hljs-keyword">if</span> (e.code === <span class="hljs-string">"Space"</span>) {
    playNpauseFn();
  } <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (e.code === <span class="hljs-string">"ArrowLeft"</span>) {
    rewindNforwardFn(<span class="hljs-string">"rewind"</span>);
  } <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (e.code === <span class="hljs-string">"ArrowRight"</span>) {
    rewindNforwardFn(<span class="hljs-string">"forward"</span>);
  } <span class="hljs-keyword">else</span> {
    <span class="hljs-keyword">return</span>;
  }
});
</code></pre>
<p>Alternatively, you can find all the code on the <a target="_blank" href="https://github.com/DeveloperAspire/custom-html5-video-player">GitHub repository</a> I've created for this project. If you find it helpful, consider giving the repository a star – I'd really appreciate it!</p>
<p>You can access the live site by <a target="_blank" href="https://custom-html5-video-player5.netlify.app/">visiting here</a>.</p>
<h2 id="heading-where-to-go-from-here">Where to Go from Here</h2>
<p>Now that you've finished reading this article, remember that your journey doesn't end here. There's a whole world of possibilities waiting for you to explore and build upon what you've learned.</p>
<p>The Video API offers a wide range of features you can experiment with, such as adding playback rate controls, volume adjustment, or even subtitles. You can also enhance your project with animations, and interactions, and ensure it's mobile responsive, perhaps even enabling landscape mode for mobile devices.</p>
<p>For further inspiration and ideas, feel free to check out my version of the project <a target="_blank" href="https://aspire-video-player.netlify.app/">here</a> – although it's still a work in progress. I'm excited to see what you'll create! </p>
<p>If you decide to share your project, don't forget to tag me—I'd love to give it a review and offer any feedback. Keep pushing forward, and happy coding!</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>Congratulations! You've reached the end of this article and have gained valuable hands-on experience in building your own custom HTML5 video player. By incorporating keyboard navigation and optimizing for accessibility, you've ensured a seamless user experience.</p>
<p>I'm excited to see what you'll create with your newfound knowledge, so don't forget to share your projects with me.</p>
<p> Thank you for reading, and see you next time!</p>
<h3 id="heading-contact-information">Contact information</h3>
<p>Would you like to get in touch with me? Don't hesitate to reach out through any of the following channels:</p>
<ul>
<li>Twitter / X: <a target="_blank" href="https://twitter.com/developeraspire">@developeraspire</a></li>
<li>Email: developeraspire5@gmail.com</li>
</ul>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Use Callbacks and Higher Order Functions in JavaScript ]]>
                </title>
                <description>
                    <![CDATA[ The way functions are treated and used in JavaScript is quite interesting. They are very flexible – we can assign functions as a value to a variable, return them as a value from another function, and pass them as an argument to another function. We c... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/callbacks-higher-order-functions-in-javascript/</link>
                <guid isPermaLink="false">66ba596fbca875d7790d6a90</guid>
                
                    <category>
                        <![CDATA[ callbacks ]]>
                    </category>
                
                    <category>
                        <![CDATA[ functions ]]>
                    </category>
                
                    <category>
                        <![CDATA[ JavaScript ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Franklin Okolie ]]>
                </dc:creator>
                <pubDate>Fri, 12 Jan 2024 18:07:08 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2024/01/higher-order-callbacks.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>The way functions are treated and used in JavaScript is quite interesting. They are very flexible – we can assign functions as a value to a variable, return them as a value from another function, and pass them as an argument to another function. We can do all this because JavaScript treats functions as <strong>first class citizens</strong>.</p>
<p>In this article, I'll go over what higher order functions and callbacks are, and how they work in JavaScript.</p>
<h2 id="heading-functions-as-first-class-citizens-in-javascript">Functions as First Class Citizens in JavaScript</h2>
<p>Functions are defined as <a target="_blank" href="https://developer.mozilla.org/en-US/docs/Glossary/First-class_Function">first class citizens</a> or first class objects in JavaScript because functions are treated like variables.</p>
<p>This means that functions in JavaScript can be:</p>
<ul>
<li>Passed as an argument to a another function.</li>
<li>Assigned as a value to a variable.</li>
<li>Returned as a value from a function.</li>
</ul>
<p>It is essential to understand how functions are treated in JavaScript, as they serve as a building block to understanding higher order and callback functions in JavaScript and how they work.</p>
<h2 id="heading-what-are-higher-order-functions">What are Higher Order Functions?</h2>
<p>Higher order functions are functions that take functions as arguments and also return a function as a value. </p>
<p>There are a lot of built-in higher order functions provided in JavaScript. We'll take a look at some and take advantage of how functions are treated as first class citizens. We'll also create our own higher order functions.</p>
<p>First, let's take a look at some examples of built-in higher order functions.</p>
<h3 id="heading-array-methods">Array Methods</h3>
<p>Array methods are usually the first introduction of higher order functions a developer will have when learning JavaScript. These include, but are not limited to, the <code>map</code>, <code>filter</code>, <code>forEach</code>, <code>find</code>, <code>findIndex</code>, <code>some</code>, and <code>every</code> array methods provided by JavaScript.  </p>
<p>These array methods or functions have a lot in common, but one of the most common feature is that they all accept a function as an argument. Below is a code snippet that demonstrates how the <code>forEach</code> array method works:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> people = [
  { <span class="hljs-attr">firstName</span>: <span class="hljs-string">"Jack"</span>, <span class="hljs-attr">year</span>: <span class="hljs-number">1988</span> },
  { <span class="hljs-attr">name</span>: <span class="hljs-string">"Kait"</span>, <span class="hljs-attr">year</span>: <span class="hljs-number">1986</span> },
  { <span class="hljs-attr">name</span>: <span class="hljs-string">"Irv"</span>, <span class="hljs-attr">year</span>: <span class="hljs-number">1970</span> },
  { <span class="hljs-attr">name</span>: <span class="hljs-string">"Lux"</span>, <span class="hljs-attr">year</span>: <span class="hljs-number">2015</span> },
];

people.forEach(<span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">person</span>) </span>{
  <span class="hljs-built_in">console</span>.log(person);
});

<span class="hljs-comment">// Output:  Logs every person object in the array</span>
</code></pre>
<p>From the code sample above, we can see that the <code>forEach</code> method accepts a function as an argument which it calls on every iteration on the array. Therefore the <code>forEach</code> array method is a higher order function.</p>
<h3 id="heading-timer-events">Timer Events</h3>
<p>Another set of commonly used built-in higher order functions are the <code>setInterval</code> and <code>setTimeout</code> functions, known as timer events in JavaScript.</p>
<p>Each function accepts a function as one of its arguments and uses it to create a timed event.</p>
<p>Take a look at the code sample below to see how <code>setTimeout</code> works:</p>
<pre><code class="lang-javascript"><span class="hljs-built_in">setTimeout</span>(<span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params"></span>) </span>{
  <span class="hljs-built_in">console</span>.log(<span class="hljs-string">"This is a higher order function"</span>);
}, <span class="hljs-number">1000</span>);

<span class="hljs-comment">// Output: "This is a higher order function" after 1000ms / 1 second</span>
</code></pre>
<p>The code snippet above is the most basic example of how a <code>setTimeout</code> function works. It accepts a function and a time duration in milliseconds and executes the function after the provided duration has passed. </p>
<p>From the example above, <code>This is a higher order function</code> is printed to the console after 1000 ms, or one second.</p>
<pre><code class="lang-javascript"><span class="hljs-built_in">setInterval</span>(<span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params"></span>) </span>{
  <span class="hljs-built_in">console</span>.log(<span class="hljs-string">"This is a higher order function"</span>);
}, <span class="hljs-number">1000</span>);

<span class="hljs-comment">// Output: "This is a higher order function" after every 1000ms / 1 second</span>
</code></pre>
<p>The <code>setInterval</code> function is similar to the <code>setTimeout</code> function, just like the array methods – although it functions differently. But we can see a common pattern: it also accepts a function as one of its parameters.</p>
<p>Unlike <code>setTimeout</code> (that executes the function after the provided duration has passed), <code>setInterval</code> executes the function over and over again every 1000ms or 1 second.</p>
<h3 id="heading-how-to-create-and-use-a-higher-order-function">How to Create and Use a Higher Order Function</h3>
<p>Higher order functions are not limited to the built-in ones provided by JavaScript.</p>
<p>Since functions in JavaScript are treated as first class objects, we can take advantage of this behavior and build highly performant and reusable functions.</p>
<p>In the examples below, we'll build a couple of functions. They'll accept the name of a customer and a greeting, and then print that info to the console.</p>
<p>First, here is a simple function that does both of those things:</p>
<pre><code class="lang-js"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">greetCustomer</span>(<span class="hljs-params">firstName, lastName, salutation</span>) </span>{
  <span class="hljs-keyword">const</span> fullName = <span class="hljs-string">`<span class="hljs-subst">${firstName}</span> <span class="hljs-subst">${lastName}</span>`</span>;

  <span class="hljs-built_in">console</span>.log(<span class="hljs-string">`<span class="hljs-subst">${salutation}</span> <span class="hljs-subst">${fullName}</span>`</span>);
}

greetCustomer(<span class="hljs-string">"Franklin"</span>, <span class="hljs-string">"Okolie"</span>, <span class="hljs-string">"Good Day"</span>);

<span class="hljs-comment">// Output: "Good Day Franklin Okolie"</span>
</code></pre>
<p><code>greetCustomer</code> accepts 3 arguments: a first name, a last name, and a salutation. Then it prints a greeting to the customer to the console.</p>
<p>But there is a problem with this function – it's doing two things: composing the full name of the customer and also printing the greeting.</p>
<p>This is not a best practice, as functions should do only one thing and do it well. So we are going to refactor our code.</p>
<p>Another function should compose the customer's name so that the <code>greetCustomer</code> function only has to print the greeting to the console. So let's write a function that handles that:</p>
<pre><code class="lang-js"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">composeName</span>(<span class="hljs-params">firstName, lastName</span>) </span>{
  <span class="hljs-keyword">const</span> fullName = <span class="hljs-string">`<span class="hljs-subst">${firstName}</span> <span class="hljs-subst">${lastName}</span>`</span>;

  <span class="hljs-keyword">return</span> fullName;
}
</code></pre>
<p>Now that we have a function that combines the customer's first and last names, we can use that function in <code>greetCustomer</code>:</p>
<pre><code class="lang-js"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">greetCustomer</span>(<span class="hljs-params">composerFunc, firstName, lastName, salutation</span>) </span>{
  <span class="hljs-keyword">const</span> fullName = composerFunc(firstName, lastName);

  <span class="hljs-built_in">console</span>.log(<span class="hljs-string">`<span class="hljs-subst">${salutation}</span> <span class="hljs-subst">${fullName}</span>`</span>);
}

greetCustomer(composeName, <span class="hljs-string">"Franklin"</span>, <span class="hljs-string">"Okolie"</span>, <span class="hljs-string">"Good Day"</span>);

<span class="hljs-comment">// Output: "Good Day Franklin Okolie"</span>
</code></pre>
<p>Now this looks cleaner, and each function does just one thing. The <code>greetCustomer</code> function now accept 4 arguments, and since one of those arguments is a function, it's now a higher order function.</p>
<p>You might have wondered earlier, how is a function being invoked inside of another function, and why?</p>
<p>Now we'll take a deep dive into function invocation and answer both of those questions.</p>
<h3 id="heading-returning-a-function-as-a-value">Returning a Function as a Value</h3>
<p>Remember that higher order functions either take a function as a parameter and/or return a function as a value.</p>
<p>Let's refactor the <code>greetCustomer</code> function to use fewer arguments and return a function:</p>
<pre><code class="lang-js"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getGreetingsDetails</span>(<span class="hljs-params">composerFunc, salutation</span>) </span>{
  <span class="hljs-keyword">return</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">greetCustomer</span>(<span class="hljs-params">firstName, lastName</span>) </span>{
    <span class="hljs-keyword">const</span> fullName = composerFunc(firstName, lastName);

    <span class="hljs-built_in">console</span>.log(<span class="hljs-string">`<span class="hljs-subst">${salutation}</span> <span class="hljs-subst">${fullName}</span>`</span>);
  };
</code></pre>
<p>The last version of <code>greetCustomer</code> accepted too many arguments. Four arguments isn't a lot, but it would still be frustrating if you messed up the order of the arguments. Generally, the fewer arguments you have, the better.</p>
<p>So in the example above, we have a function called <code>getGreetingDetails</code> which accepts <code>composerFunc</code> and <code>salutation</code> on behalf of the inner <code>greetCustomer</code> function. It then returns the inner <code>greetCustomer</code> function, which itself accepts <code>firstName</code> and <code>lastName</code> as arguments.</p>
<p>By doing this, <code>greetCustomer</code> has fewer arguments overall.</p>
<p>And with that, let's take a look at how to use the <code>getGreetingDetails</code> function:</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> greet = getGreetingsDetails(composeName, <span class="hljs-string">"Happy New Year!"</span>);

greet(<span class="hljs-string">"Quincy"</span>, <span class="hljs-string">"Larson"</span>);

<span class="hljs-comment">// Output: "Happy New Year Quincy Larson"</span>
</code></pre>
<p>Now take a step back and admire this beautiful abstraction. Marvelous! We have used the magic of higher order functions to simplify the <code>greetCustomer</code> function.</p>
<p>Let's walk through how everything works. The higher order function named <code>getGreetingDetails</code> takes in two arguments: a function to compose the customer's first and last name, and a salutation. Then it returns a function named <code>greetCustomer</code> which accepts the first and last name of a customer as arguments.</p>
<p> The returned <code>greetCustomer</code> function also uses the argument accepted by <code>getGreetingDetails</code> to execute some actions, too.</p>
<p>At this point you're probably wondering, how can a returned function use arguments provided to a parent function? Especially given how the function execution context works. It's possible because of <a target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Closures">closures</a>. Let's learn more about them now.</p>
<h3 id="heading-closures-explained">Closures Explained</h3>
<p>A closure is a function that has access to the variable in the scope where it was created even after the scope doesn't exist anymore in the execution context. This is one of the underlying mechanism of callbacks, as callbacks can still reference and use variables created in an outer function after that outer function has been closed.</p>
<p>Let's take a quick example:</p>
<pre><code class="lang-js"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getTwoNumbers</span>(<span class="hljs-params">num1, num2</span>) </span>{
  <span class="hljs-keyword">return</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">add</span>(<span class="hljs-params"></span>) </span>{
    <span class="hljs-keyword">const</span> total = num1 + num2;
    <span class="hljs-built_in">console</span>.log(total);
  };
}

<span class="hljs-keyword">const</span> addNumbers = getTwoNumbers(<span class="hljs-number">5</span>, <span class="hljs-number">2</span>);

addNumbers();

<span class="hljs-comment">//Output: 7;</span>
</code></pre>
<p>The code in this example defines a function called <code>getTwoNumbers</code> and shows you how closures work. Let's explore it in more detail:</p>
<ol>
<li><code>getTwoNumbers</code> is defined as a function that takes two parameters, <code>num1</code> and <code>num2</code>.</li>
<li>Inside <code>getTwoNumbers</code>, it returns another function, which is an inner function named <code>add</code>.</li>
<li>The <code>add</code> function, when invoked, calculates the sum of <code>num1</code> and <code>num2</code> and logs the result to the console.</li>
<li>Outside the <code>getTwoNumbers</code> function, we create a variable called <code>addNumbers</code> and assign it the result of invoking <code>getTwoNumbers(5, 2)</code>. This effectively sets up a closure where <code>addNumbers</code> now "remembers" the values <code>5</code> and <code>2</code> as <code>num1</code> and <code>num2</code>.</li>
<li>Finally, we call <code>addNumbers()</code> to execute the inner <code>add</code> function. Since <code>addNumbers</code> is a closure, it still has access to the <code>num1</code> and <code>num2</code> values, which were set to <code>5</code> and <code>2</code>, respectively. It calculates their sum and logs <code>7</code> to the console.</li>
</ol>
<p>If you want to learn more about <a target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Closures">closures, read more here</a>.</p>
<p>Back to our higher order function. The returned function <code>greetCustomer</code> gets returned as a value which we store in a variable named <code>greet</code>.</p>
<p>Doing that makes the <code>greet</code> variable itself a function, meaning we can invoke it as a function and pass in arguments for a first and last name.</p>
<p>And violà There you have it. These concepts can be a bit complex to grasp at first, but once you get the hang of them, they never leave you.</p>
<p>I encourage you to read through the previous sections again, play with the code in your editor, and to get the hang of how everything works together.</p>
<p>Now that you have an in-depth understanding about how higher order functions work, let's talk about callback functions.</p>
<h2 id="heading-what-are-callback-functions">What are Callback Functions?</h2>
<p>A callback function is a function that is passed into another function as an argument.</p>
<p>Again, one of the defining factors of functions as first class citizens is its ability to be passed as an argument to another function. This is called the <strong>act of passing callbacks</strong>.</p>
<p>Let go back and take a look at the timing events we discussed earlier when we were learning about the built-in functions provided in JavaScript. Here's the <code>setTimeout</code> function again:</p>
<pre><code class="lang-js"><span class="hljs-built_in">setTimeout</span>(<span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params"></span>) </span>{
  <span class="hljs-built_in">console</span>.log(<span class="hljs-string">"This is a higher order function"</span>);
}, <span class="hljs-number">1000</span>);

<span class="hljs-comment">// Output: "This is a higher order function" after 1000ms / 1 seconds</span>
</code></pre>
<p>We've established that the <code>setTimeout</code> function is a higher order function because it accepts another function as an argument.</p>
<p>The function that's passed as an argument to the <code>setTimeout</code> function is called a callback function. This is because it is invoked or executed inside of the higher order function it's passed into.</p>
<p>To get a better understanding of callback functions, let's take another look at the <code>greetCustomer</code> function from earlier:</p>
<pre><code class="lang-js"><span class="hljs-comment">// THIS IS A CALLBACK FUNCTION</span>
<span class="hljs-comment">// IT IS PASSED AS AN ARGUMENT TO A FUNCTION</span>

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">composeName</span>(<span class="hljs-params">firstName, lastName</span>) </span>{
  <span class="hljs-keyword">const</span> fullName = <span class="hljs-string">`<span class="hljs-subst">${firstName}</span> <span class="hljs-subst">${lastName}</span>`</span>;

  <span class="hljs-keyword">return</span> fullName;
}

<span class="hljs-comment">// THIS IS A HIGHER ORDER FUNCTION</span>
<span class="hljs-comment">// IT ACCPEPTS A FUNCTION AS A ARGUMENT</span>

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">greetCustomer</span>(<span class="hljs-params">composerFunc, firstName, lastName, salutation</span>) </span>{
  <span class="hljs-keyword">const</span> fullName = composerFunc(firstName, lastName);

  <span class="hljs-built_in">console</span>.log(<span class="hljs-string">`<span class="hljs-subst">${salutation}</span> <span class="hljs-subst">${fullName}</span>`</span>);
}

greetCustomer(composeName, <span class="hljs-string">"Franklin"</span>, <span class="hljs-string">"Okolie"</span>, <span class="hljs-string">"Good Day"</span>);

<span class="hljs-comment">// Output: "Good Day Franklin Okolie"</span>
</code></pre>
<p>The <code>composeName</code> is a callback function that is passed as an argument into the <code>greetCustomer</code> function a higher order function and it is executed inside this function.</p>
<h2 id="heading-the-difference-between-higher-order-functions-and-callback-functions">The Difference Between Higher Order Functions and Callback Functions</h2>
<p>It's important that we understand the difference between these two terms so we can communicate more clearly with teammates and during technical interviews:</p>
<ul>
<li><strong>Higher Order Function</strong>: A function that accepts a function as an argument and/or returns a function as its value.</li>
<li><strong>Callback Function</strong>: A function that's passed as a argument to another function.</li>
</ul>
<h3 id="heading-a-bag-and-book">A Bag and Book</h3>
<p>To further understand these terms, I'll share a simple analogy.</p>
<p>Imagine you have a bag and a book. You carry the book in your bag while attending a meeting, going to class, going to church, and so on.</p>
<p>In this scenario, the bag accepts your book to carry it, and also returns it when you want to use it. So the bag is like a higher order function.</p>
<p>The book is kept inside of the bag until it's ready to be used, so it's like a callback function.</p>
<h3 id="heading-fuel-and-fuel-tank">Fuel and Fuel Tank</h3>
<p>Let's take a look at another analogy; fuel and a fuel tank.</p>
<p>To fuel a car, we have to pour the fuel through the fuel tank, the fuel tank recieves the fuel – just like a higher order function.</p>
<p>The fuel is poured into the fuel tank – like a callback function.</p>
<p>I hope these analogies help to further simplify higher order and callback functions and the difference between them.</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>As you can see, functions in JavaScript are very flexible, and can be used in a lot of helpful ways. This flexibility also lead to two common technical terms in JavaScript, higher order functions and callback functions.</p>
<p>If you want to learn more about these topics, check out the MDN documentation on functions as <a target="_blank" href="https://developer.mozilla.org/en-US/docs/Glossary/First-class_Function">first class citizens</a>, <a target="_blank" href="https://developer.mozilla.org/en-US/docs/Glossary/First-class_Function">higher order functions</a>, and <a target="_blank" href="https://developer.mozilla.org/en-US/docs/Glossary/Callback_function">callback functions</a>.</p>
<p>I hope you learned a lot from this article, and I hope you use your newfound knowledge to communicate your thoughts more clearly during pair coding sessions or during technical interviews.</p>
<p>For more JavaScripts tips, follow me on <a target="_blank" href="https://twitter.com/developeraspire">Twitter</a>.</p>
<p>Thanks for reading! See you next time.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ JavaScript Operators and Operator Precedence – Beginner's Guide ]]>
                </title>
                <description>
                    <![CDATA[ A few months ago, I attempted to solve a math problem in my head before writing it in JavaScript. It was then that I received the most stunning revelation of my career, which was both shocking and eye-opening.  So what did I attempt to do? I made the... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/javascript-operators-and-operator-precedence/</link>
                <guid isPermaLink="false">66ba5974f4ac8da2b2c2e85c</guid>
                
                    <category>
                        <![CDATA[ JavaScript ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Franklin Okolie ]]>
                </dc:creator>
                <pubDate>Mon, 20 Mar 2023 21:15:49 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2023/03/JavaScript_Operator_precedence.jpg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>A few months ago, I attempted to solve a math problem in my head before writing it in JavaScript. It was then that I received the most stunning revelation of my career, which was both shocking and eye-opening. </p>
<p>So what did I attempt to do? I made the following mental arithmetic calculations:</p>
<pre><code class="lang-js"><span class="hljs-number">2</span> + <span class="hljs-number">3</span> * <span class="hljs-number">4</span>
</code></pre>
<p>Naturally, my response was <code>20</code>, so I proceeded to code it. But when the output on the console revealed the answer to be <code>14</code>, it completely altered how I thought about JavaScript.</p>
<p>But how did I perform arithmetic operations before JavaScript? Well, I just entered the relevant numbers into a calculator and waited for my results. Easy! </p>
<p>How inaccurate my mental model was about how mathematical operations are carried out in JavaScript was made clear by mentally performing the calculations.</p>
<p>As a JavaScript developer, you may have encountered this type of "error" when doing mathematics in your head versus how JavaScript or your calculator does it. It's not magic, but rather a simple concept known as <strong>Operator Precedence.</strong></p>
<p>In this article, we'll go over what operators are and how operators in JavaScript are parsed. This will help you not only with JavaScript but also with other programming languages if you choose to learn them.</p>
<h2 id="heading-what-are-operators">What are Operators?</h2>
<p>Operators are special symbols used to perform operations on operands, which can be variables or values. For example, in 13 / 3, the "/" division symbol serves as the operator, while "13" and "3" serve as operands.</p>
<p>A value or variable on which operators conduct operations is known as an operand. This is a little exercise to put yourself to the test. Examine the code snippet below and distinguish between operators and operands:</p>
<pre><code class="lang-js"><span class="hljs-number">1.</span> <span class="hljs-number">2</span> + <span class="hljs-number">5</span> * <span class="hljs-number">3</span>
<span class="hljs-number">2.</span> (<span class="hljs-number">12</span> + <span class="hljs-number">4</span>) / <span class="hljs-number">4</span>
<span class="hljs-number">3.</span> <span class="hljs-number">20</span> ** <span class="hljs-number">4</span> - <span class="hljs-number">4</span>

<span class="hljs-comment">/* ANSWERS
  Operators from the above operations are "+", "*" , "()", "**", "/" and "-"

 The numbers are the operands of the operation

 */</span>
</code></pre>
<h2 id="heading-types-of-operators-in-javascript">Types of Operators in JavaScript</h2>
<p>Not all operators in JavaScript perform arithmetic operations. Rather, operators vary in their functions. In this section we will look at some of the different types of operators and how they work in JavaScript.</p>
<h3 id="heading-arithmetic-operators">Arithmetic Operators</h3>
<p>An arithmetic operator is used to perform basic mathematical operations. It takes numerical values as operands, which can be variables or literals, and returns a value.</p>
<p> Arthmetic operators in JavaScript include:</p>
<ul>
<li>Addition (+) </li>
<li>Subtraction (-)</li>
<li>Multiplication (*)</li>
<li>Exponentiation (**)</li>
<li>Modulus (%)</li>
<li>Decrement (--)</li>
<li>Increment (++)</li>
<li>Division (/)</li>
</ul>
<p>The following code snippet contains example operations that use the arithmetic operators:</p>
<pre><code class="lang-js"><span class="hljs-number">2</span> + <span class="hljs-number">3</span>   <span class="hljs-comment">// ANSWER: 5. This adds the operands.</span>

<span class="hljs-number">10</span> * <span class="hljs-number">5</span> <span class="hljs-comment">// ANSWER: 50. This multiplies the operands.</span>

<span class="hljs-number">10</span> % <span class="hljs-number">3</span> <span class="hljs-comment">// ANSWER: 1. This returns the remainder of dividing the two operands.</span>

<span class="hljs-number">10</span>++   <span class="hljs-comment">// ANSWER: 11. This increases the operands by 1.</span>

<span class="hljs-number">100</span>-- <span class="hljs-comment">// ANSWER: 9. This decreases the operands by 1</span>

<span class="hljs-number">10</span> ** <span class="hljs-number">3</span> <span class="hljs-comment">// ANSWER: 1000. This multiplies the operands by the power of 3 ( 10 * 10 * 10)</span>

<span class="hljs-number">10</span> - <span class="hljs-number">3</span> <span class="hljs-comment">// ANSWER: 7. This substracts the operands</span>

<span class="hljs-number">10</span> / <span class="hljs-number">5</span> <span class="hljs-comment">//ANSWER: 2. This divides 10 by 5</span>
</code></pre>
<h3 id="heading-comparison-operators">Comparison Operators</h3>
<p>A comparison operator compares two operands and returns a Boolean (true or false) value as a result of the comparison.</p>
<p>The JavaScript comparison operators are as follows:</p>
<ul>
<li>Equals (==)</li>
<li>Not Equal (!=)</li>
<li>Strict Equal (===)</li>
<li>Strict Not Equal (!==)</li>
<li>Greater than (&gt;)</li>
<li>Greater than or equal (&gt;=)</li>
<li>Less than (&lt;)</li>
<li>Less than or equal (&lt;=)</li>
</ul>
<p>The code snippet below provides some examples of how the comparison operators operate:</p>
<pre><code class="lang-js"><span class="hljs-number">10</span> == <span class="hljs-number">10</span>  <span class="hljs-comment">// ANSWER: True. It returns true because 10 is equal to 10.</span>

<span class="hljs-number">10</span> != <span class="hljs-number">7</span> <span class="hljs-comment">// ANSWER: True. It returns a Truthy value because 10 is not equal to 7.</span>

<span class="hljs-number">10</span> == <span class="hljs-string">"10"</span> <span class="hljs-comment">//ANSWER: True. It returns true because 10 equals 10.</span>

<span class="hljs-number">10</span> === <span class="hljs-string">"10"</span> <span class="hljs-comment">//ANSWER: False. This returns false because 10, which is of type number, is not equal to "10" which is of type string. It compares them strictly by their values and by their type.</span>

<span class="hljs-number">10</span> !== <span class="hljs-string">"10"</span> <span class="hljs-comment">// ANSWER: True. It returns a Truthy value because 10, which is of type number, is not equal to "10", which of type string.</span>

<span class="hljs-number">10</span> &gt; <span class="hljs-number">30</span>  <span class="hljs-comment">//ANSWER: False. It returns false because 10 is not greater than 30.</span>

<span class="hljs-number">10</span> &lt; <span class="hljs-number">50</span> <span class="hljs-comment">//ANSWER: True. This returns a truthy value because 10 is less than 50.</span>

<span class="hljs-number">10</span> &gt;= <span class="hljs-number">70</span>  <span class="hljs-comment">//ANSWER: False. This will return a falsly value because 10 is not greater than 70, nor is it equal to 70.</span>

<span class="hljs-number">10</span> &lt;= <span class="hljs-number">34</span> <span class="hljs-comment">//ANSWER: True. This is true because 10 is less than 34 (even though it's not equal to 34 - it's "less than or equal to").</span>
</code></pre>
<h3 id="heading-assignment-operators">Assignment Operators</h3>
<p>Based on the value of its right operand, an assignment operator assigns a value to its left operand. The most fundamental application is the use of the assignment operator (=) to assign a value to a variable. It essentially assigns the value of one operand to another.</p>
<p>The code snippet below provides some examples of how the assignment operator works:</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> author = <span class="hljs-string">"Franklin"</span>

<span class="hljs-keyword">const</span> platform = <span class="hljs-string">"Freecodecamp"</span>

<span class="hljs-keyword">const</span> age = <span class="hljs-number">78</span>
</code></pre>
<p>Let's look at some further assignment operator examples:.</p>
<ul>
<li>Assignment (=)</li>
<li>Addition Assignment (+=)</li>
<li>Subtraction Assignment (-=)</li>
<li>Division Assignment (/=)</li>
<li>Multiplication Assignment (*=)</li>
<li>Exponentiation Assignment (**=)</li>
<li>Modulus Assignment (%=)</li>
</ul>
<p>It's important to remember that when employing assignment operators other than the "=" operator—which I like to refer to as "arthmetic assignments"—that they also carry out an arthmetic operation before assigning the value to the operand. </p>
<p>To see an example of it in action, look at the code below:</p>
<pre><code class="lang-js"><span class="hljs-keyword">let</span> people = <span class="hljs-number">20</span>;

people += <span class="hljs-number">20</span>

<span class="hljs-built_in">console</span>.log(people) <span class="hljs-comment">// OUTPUT: 40</span>

<span class="hljs-keyword">let</span> cars = <span class="hljs-number">30</span>

cars -= <span class="hljs-number">20</span>

<span class="hljs-built_in">console</span>.log(cars) <span class="hljs-comment">//OUTPUT: 10</span>
</code></pre>
<p>We can see from the code excerpt above that the arthimetic operations were first performed on the operands before they were assigned, using the appropriate arithmetic operators. </p>
<p>The "arithmetic assignments" basically operate as follows: JavaScript first executes the arithmetic operation, then it assigns the value of the operation to the operand (variable).</p>
<p>After seeing how that operates, let's learn more about the various operators and how to use them:</p>
<pre><code class="lang-js"><span class="hljs-keyword">let</span> result = <span class="hljs-number">400</span>;  <span class="hljs-comment">//The Assignment operator was used to assign the value 400 to the variable result.</span>

result += <span class="hljs-number">20</span>; 
consle.log(result)  <span class="hljs-comment">//OUTPUT: 420. The value of the left operand was added to 20 and the value assigned to the left operand. (400 + 20)</span>

result -= <span class="hljs-number">20</span>; 
consle.log(result)  <span class="hljs-comment">//OUTPUT: 400. The value of the right operand was subtracted from the left operand the value assigned to the left operand. (420 - 20)</span>

result *= <span class="hljs-number">10</span> 
consle.log(result)  <span class="hljs-comment">//OUTPUT: 4000. The values of both operands are multiplied and the value from the operation is assigned to the left operand.</span>

result /= <span class="hljs-number">10</span>; 
consle.log(result)  <span class="hljs-comment">//OUTPUT: 400. The left operand is divided by 10 and the value from the operation is assigned to the left operand.</span>

result %= <span class="hljs-number">21</span>;
consle.log(result)  <span class="hljs-comment">//OUTPUT: 21. The left operand is divided by 21 and the remainder from the operation is assigned to the left operand.</span>

result **= <span class="hljs-number">2</span>; 
consle.log(result)  <span class="hljs-comment">//OUTPUT: 440. The left operand is raised by the power of 2 and the value is assigned to the left operand.</span>
</code></pre>
<p>Let's move on to the next type of operator now that we have seen how the assignment operators function and how we may use them.</p>
<h3 id="heading-logical-operators">Logical Operators</h3>
<p>When used with boolean values, a logical operator produces a boolean value (true or false), otherwise it returns the value of one of the operands. Logical operators are used to check and determine the logic between two or more operands.</p>
<p>Although they can be difficult to understand, let's go over the operators and see how they function:</p>
<ul>
<li>OR (| |)</li>
<li>AND (&amp;&amp;)</li>
<li>NOT (!)</li>
</ul>
<p>Examples of the operators in use are provided below:</p>
<pre><code class="lang-js"><span class="hljs-comment">// USING THE AND(&amp;&amp;) OPERATOR</span>

<span class="hljs-keyword">let</span> canDrive = <span class="hljs-literal">true</span>;
<span class="hljs-keyword">let</span> hasLicense = <span class="hljs-literal">false</span>;

<span class="hljs-keyword">const</span> readyToDrive = canDrive &amp;&amp; hasLicense;

<span class="hljs-built_in">console</span>.log(readyToDrive) <span class="hljs-comment">//OUTPUT: false</span>
</code></pre>
<p>With the help of the code snippet above, we were able to construct a logic that determines whether a person is qualified to drive if they possess a driver's license and have driving experience. Both requirements must be satisfied before the person can pass the eligibility test.</p>
<p>The AND (&amp;&amp;) operator determines this because if one of the requirements is false, the operation's result will also be false. The operation cannot produce a truthy value unless both values are true:</p>
<pre><code class="lang-js"><span class="hljs-comment">// USING THE AND(&amp;&amp;) OPERATOR</span>

<span class="hljs-keyword">let</span> canDrive = <span class="hljs-literal">true</span>;
<span class="hljs-keyword">let</span> hasLicense = <span class="hljs-literal">true</span>;

<span class="hljs-keyword">const</span> readyToDrive = canDrive &amp;&amp; hasLicense;

<span class="hljs-built_in">console</span>.log(readyToDrive) <span class="hljs-comment">// OUTPUT: true</span>
</code></pre>
<p>Next, given the identical scenario as earlier, let's investigate how we can use the OR(||) operator:</p>
<pre><code class="lang-js"><span class="hljs-comment">// USING THE OR(||) OPERATOR</span>

<span class="hljs-keyword">let</span> canDrive = <span class="hljs-literal">true</span>;
<span class="hljs-keyword">let</span> hasLicense = <span class="hljs-literal">false</span>;

<span class="hljs-keyword">const</span> readyToDrive = canDrive || hasLicense;

<span class="hljs-built_in">console</span>.log(readyToDrive) <span class="hljs-comment">// OUTPUT: true</span>
</code></pre>
<p>As an illustration, the eligibility regulations were changed to permit those who lack a license to drive as long as they are capable of doing so. </p>
<p>We created a logic that tests this using the OR (||) operator. If one of the operands is a true value, the operation returns true, indicating that in this case the person has passed the eligibility test and is permitted to drive.</p>
<p>You might find it difficult to determine whether an operation returns true or false when using logical operators, so I made a little cheat sheet you can memorize and refer to whenever you get stuck:</p>
<pre><code class="lang-js"><span class="hljs-comment">// AND(&amp;&amp;) Operator cheatsheet.</span>

<span class="hljs-literal">true</span> &amp;&amp; <span class="hljs-literal">false</span> = <span class="hljs-literal">false</span>;
<span class="hljs-literal">false</span> &amp;&amp; <span class="hljs-literal">false</span> = <span class="hljs-literal">false</span>;
<span class="hljs-literal">true</span> &amp;&amp; <span class="hljs-literal">true</span> = <span class="hljs-literal">true</span>
</code></pre>
<pre><code class="lang-js"><span class="hljs-comment">// OR(||) Operator cheatsheet.</span>

<span class="hljs-literal">true</span> || <span class="hljs-literal">false</span> = <span class="hljs-literal">true</span>;
<span class="hljs-literal">false</span> || <span class="hljs-literal">false</span> = <span class="hljs-literal">false</span>;
<span class="hljs-literal">true</span> || <span class="hljs-literal">true</span> = <span class="hljs-literal">true</span>
</code></pre>
<p>If the above is too long for you to memorize, here is another cheat sheet that is as simple:</p>
<pre><code class="lang-js"><span class="hljs-literal">false</span> &amp;&amp; anything = <span class="hljs-literal">false</span>;
<span class="hljs-literal">true</span> || anything = <span class="hljs-literal">true</span>;
</code></pre>
<p>Hopefully, these little tips will serve as a reference as you utilize the logical operators in JavaScript.</p>
<p>Check out the code sample below for an example of how to use the NOT(!) operator, which is the last logical operator on the list:</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> author = <span class="hljs-string">"Franklin"</span>

<span class="hljs-keyword">if</span> (author != <span class="hljs-string">"Franklin) {
    console.log("</span>This is not the author<span class="hljs-string">")
}</span>
</code></pre>
<p>We created a basic program from the above code snippet that checks the author of an article or book and outputs a message if the author does not match the original author of the book. The NOT (!) operator is typically combined with other operators to create useful operations.</p>
<p>You can also use it to determine whether a value is true or false by inverting a Boolean value. Let's take a look at how that works below, using the driving eligibility test scenario:</p>
<pre><code class="lang-js"><span class="hljs-comment">// USING THE NOT(!) OPERATOR</span>

<span class="hljs-keyword">let</span> canDrive = <span class="hljs-literal">true</span>;
<span class="hljs-keyword">let</span> hasLicense = <span class="hljs-literal">false</span>;

<span class="hljs-keyword">if</span> (!canDrive &amp;&amp; !hasLicense) {
     <span class="hljs-built_in">console</span>.log(<span class="hljs-string">"Sorry, you are not eligible to drive"</span>)
}

<span class="hljs-comment">//OUTPUT: "Sorry, you are not eligible to drive"</span>
</code></pre>
<p>Let us break down the logic. First, we have a person who knows how to drive but does not have a driver's license, which is required by law for a person to be eligible to drive.</p>
<p>We created logic to ensure that if a person lacks either of the two qualities, they are not permitted to drive. The preceding logic can be translated as follows:</p>
<p>"If a person CANNOT drive and DOES NOT have a driver's license, they are not allowed to drive".</p>
<p>Because the variables declared <code>canDrive</code> is <code>true</code> so the <code>!canDrive</code> inverts to <code>false</code> and the <code>hasLicense</code> is <code>false</code>, it inverts to <code>true</code>.</p>
<p>So how does it end up being false? Remember our cheatsheet from earlier? We can use it to check the outcome of the operation.</p>
<p><code>false</code> &amp;&amp; <code>true</code> will be <code>false</code>.</p>
<p>If you have read this far into the article, congratulations on your new knowledge of JavaScript operators. If you would like to explore further and see more types of operators, here is a link to an <a target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Expressions_and_Operators">MDN resource</a>. Operators are crucial in our day-to-day activities with JavaScript, so learning about them is important.</p>
<p>Now we can go on to the next section of this article where you will learn how you can utilize several operators in an operation and how JavaScript calculates this operation.</p>
<h2 id="heading-operator-precedence-in-javascript">Operator Precedence in JavaScript</h2>
<p>The concept of operator precedence describes how operators are compared to one another throughout an operation. Operators that have higher precedence are given a higher priority than the operators with lower precedence.</p>
<p>Aside from writing basic logic in JavaScript every day, we spend about half of our time writing complex mathematical operations, logical operations, and occasionally we even translate some physics and math formulas into JavaScript code. This causes significant complications because neither of the aforementioned formulas are simple – they both contain multiple operators and operands.</p>
<p>But how does JavaScript parse this condition when it encounters it? Let's see an example below:</p>
<pre><code class="lang-js"><span class="hljs-comment">/*GIVEN A SET OF SCORES GOTTEN BY A TEAM,
CALCULATE THE AVERAGE SCORE OF THE TEAM

FORMULA FOR AVERAGE IS: SUM OF VALUES DIVIDED BY TOTAL NUMBER OF VALUES

firstScore = 40;
secondScore = 38;
thridScore = 24;
fourthScore = 32; 
*/</span>

<span class="hljs-keyword">const</span> averageScore = <span class="hljs-number">40</span> + <span class="hljs-number">38</span> + <span class="hljs-number">24</span> + <span class="hljs-number">32</span> / <span class="hljs-number">4</span>;

<span class="hljs-built_in">console</span>.log(averageScore)    <span class="hljs-comment">//OUPUT: 110</span>
</code></pre>
<p>If you use any <a target="_blank" href="https://www.omnicalculator.com/math/average">online average calculator tool</a>, the result will be <code>33.5</code>, which is the right answer. The outcome of the aforementioned operation in our code is <code>110</code>, which is quite "wrong" because the average on those values cannot be <code>110</code>. Yet why? Here, operator precedence is in effect.</p>
<p>Similar to how hierarchies operate in the real world, some operators in the land of JavaScript are more significant than others. JavaScript first recognizes and uses the "more" important operators before the "less" essential ones in an operation.</p>
<h3 id="heading-rules-of-the-operator-precedence">Rules of the Operator Precedence</h3>
<p>JavaScript doesn't randomly choose which operator it grants priority to in an operation based on the order in which they appear or for any other reason. Doing so would result in a JavaScript universe plagued by mathematical inconsistencies.</p>
<p>JavaScript has a rule that it carefully adheres to in order to determine precedence. Rather to going through a lengthy table or chart of all these rules, there is a quicker method that is easier to remember: <strong>BODMAS</strong></p>
<p>BODMAS translates to:</p>
<ul>
<li>Bracket "()"</li>
<li>Of (**)</li>
<li>Division (/)</li>
<li>Multiplication (**)</li>
<li>Addition (+)</li>
<li>Subtraction(-)</li>
</ul>
<p>Each operand is listed above in the precise order that their precedence is determined. Easy? I adore this technique and employ it regularly to avoid errors that Operator precedence can introduce.</p>
<p>Let's investigate how JavaScript handled the average score operation. As we can see from the small formula above (<strong>BODMAS</strong>), the Division(/) operator has a higher precedence than the Addition(+) operator, so JavaScript first performs the Division(/) operations by dividing <code>32</code> by <code>4</code>, which results in <code>8</code>. Then it moves on to the next operator in accordance with the precedence, which is the Addition(+) operator, which sums up all the values and returns a result of 110.</p>
<p>Now let's look again at the exaxmple from the beginning of this tutorial:</p>
<pre><code class="lang-js"><span class="hljs-keyword">let</span> attendees = <span class="hljs-number">2</span> + <span class="hljs-number">3</span> * <span class="hljs-number">4</span>;

<span class="hljs-built_in">console</span>.log(attendees) <span class="hljs-comment">// OUTPUT: 14.</span>
</code></pre>
<p>You may have mentally performed the preceding computation and come up with <code>20</code> (this is what I got), but JavaScript believes otherwise, which is actually right.</p>
<p>According to the <strong>BODMAS</strong> rule of precedence, multiplication comes before addition. So JavaScript multiplied 3 by 4 (which is 12) before adding the result to the other operand to get the number 14.</p>
<p>Because we needed to divide the total count of the scores by the sum of the scores, we can now adjust our average score operation with this knowledge:</p>
<pre><code class="lang-js"><span class="hljs-comment">/*GIVEN A SET OF SCORES GOTTEN BY A TEAM,
CALCULATE THE AVERAGE SCORE OF THE TEAM

FORMULA FOR AVERAGE IS: SUM OF VALUES DIVIDED BY TOTAL NUMBER OF VALUES

 firstScore = 40;
secondScore = 38;
thridScore = 24;
fourthScore = 32; 
*/</span>

<span class="hljs-keyword">const</span> averageScore = (<span class="hljs-number">40</span> + <span class="hljs-number">38</span> + <span class="hljs-number">24</span> + <span class="hljs-number">32</span>) / <span class="hljs-number">4</span>;

<span class="hljs-built_in">console</span>.log(averageScore) <span class="hljs-comment">//OUPUT: 33.5</span>
</code></pre>
<p>Hurray! Finally, we got the correct answer! Can you tell how JavaScript interpreted this?</p>
<p>The precedence hierarchy places brackets first, so JavaScript executes the operations contained within the brackets before moving on to the next operation. As a consequence, it added 40, 38, 34, and 32 to produce 144, which was then divided by the score count of 4, giving us the final result of 33.5.</p>
<p>Here are a few exercises you can try to put your newly acquired operator precedence knowledge to the test:</p>
<pre><code class="lang-js"><span class="hljs-number">1.</span> <span class="hljs-number">2</span> + <span class="hljs-number">4</span> - <span class="hljs-number">6</span> / <span class="hljs-number">2</span>
<span class="hljs-number">2.</span> <span class="hljs-number">4</span> + <span class="hljs-number">4</span> * <span class="hljs-number">8</span> / <span class="hljs-number">3</span>
<span class="hljs-number">3.</span> <span class="hljs-number">8</span> ** <span class="hljs-number">2</span> + <span class="hljs-number">4</span>


<span class="hljs-comment">/* 
ANSWERS: 
1. 3
2. 20
3. 68
*/</span>
</code></pre>
<p>There are certain operators missing from the <strong>BODMAS</strong> formula above. The formula is not "absloute" because it only covers a tiny portion of operators, namely the arithmetic operators that we employ in our daily coding operations. This <a target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Operator_Precedence#table">MDN resource</a> shows a more thorough precedence table of hierarchy.</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>We're at the end of this tutorial, in which we learned about JavaScript operators and how JavaScript parses them when performing an operation using a technique called <strong>Operator precedence</strong>. Using this <a target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Operator_Precedence">MDN resource</a>, you can learn more about Operator precedence.</p>
<p>As it can be pretty cumbersome to remember all of the <strong>Operator precedence</strong>, so you can use the acronym <strong>BODMAS.</strong></p>
<p>I really hope you took a lot away from this article.</p>
<p>Follow me on <a target="_blank" href="https://twitter.com/developeraspire">Twitter</a>. for more tip on JavaScript and CSS.</p>
<p>I appreciate you reading. See you next time!</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How the Z-index Property Works – Stacking Order of Elements in CSS ]]>
                </title>
                <description>
                    <![CDATA[ If you're a front-end engineer, you've probably faced weird z-index bugs and ended up spending hours trying to fix them.  Change one property here and you have your header flying away from where it was meant to be.  Well, we can attribute this to the... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/z-index-property-and-stacking-order-css/</link>
                <guid isPermaLink="false">66ba597af4ac8da2b2c2e85e</guid>
                
                    <category>
                        <![CDATA[ CSS ]]>
                    </category>
                
                    <category>
                        <![CDATA[ DOM ]]>
                    </category>
                
                    <category>
                        <![CDATA[ HTML ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Web Development ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Franklin Okolie ]]>
                </dc:creator>
                <pubDate>Thu, 09 Feb 2023 22:48:03 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2023/02/stacked-books-1.jpg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>If you're a front-end engineer, you've probably faced weird z-index bugs and ended up spending hours trying to fix them. </p>
<p>Change one property here and you have your header flying away from where it was meant to be. </p>
<p>Well, we can attribute this to the fact that debugging CSS can be quite hard and most times we are doing so blindly. We change properties expecting to see the bugs magically get resolved, but they don't. </p>
<p>Unlike JavaScript that yells at you, giving you hints about what you are doing, CSS is just watches you do rubbish and quietly hopes you figure it out.</p>
<p>One of the many ways to get really good at using CSS is by researching and understanding the mechanism behind some CSS properties you use every day. </p>
<p>This will give you a clear and concise technical know-how about how to implement certain complicated designs. It'll also give you insight on how to resolve some difficult unexplainable bugs you might come across while writing code.</p>
<h2 id="heading-the-problem-with-the-z-index-property-in-css">The Problem with the Z-index Property in CSS</h2>
<p>We can all agree that one of the weirdest, most confusing, and not-so-straightforward CSS properties is the <code>z-index</code>. </p>
<p>When I started learning CSS, I was told by certain instructors that you use <code>z-index</code> when you want a certain DOM (Document Object Model) element to be on top of another. Sounds simple, right? </p>
<p>So I thought – but life experience has a way of letting us know that things aren't always as easy as we thought they'd be.</p>
<p>Not understanding how the <code>z-index</code> property actually works behind the scenes led me down a frustating rabbit hole of having unexplainable bugs relating to <code>z-index</code>. So I started cranking up the <code>z-index</code> value to enormous numbers like the infamous <code>99999</code> to see if I could get the desired result.</p>
<p>Sometimes this works, but other times it doesn't which can be the most annoying thing because it worked the other time. </p>
<p>Another situation is when it works fine at first, but then as you progress in your work, you face yet again the same problem on a different part of your app. So this has you doing the default – cranking up the new <code>z-index</code> up to <code>99999999</code>, an even bigger number than the previous one.</p>
<p>Deep down in your heart as a professional developer, you know this is not right. It is a mess (and personally, I hate messy CSS code). But you also know you have no idea how to approach the problem that will lead to a permanent fix and a win in your <code>z-index</code> wars.</p>
<p>If you are reading this article and want to understand the <code>z-index</code> once and for all, you're in the right place. </p>
<p>I'm about to help demistify the <code>z-index</code> for you. By the time you're done reading through this guide, I hope you'll know how to fix tough <code>z-index</code> bugs and how the <code>z-index</code> actually works. You'll also have a deeper and more fundamental understanding of how browsers render DOM elements and how it relates to the z-index. </p>
<p>Ready? Let's dive right in.</p>
<h2 id="heading-what-is-stacking-context-in-css">What is Stacking Context in CSS?</h2>
<p>Before we even start to understand <code>z-index</code> in all its glory, it'll be to your benefit if you can, for a moment, pretend like you don't know anything about <code>z-index</code>. Forget what you know about it, because from here on, your mental model about <code>z-index</code> is about to change.</p>
<p>There is no smoke without fire, and the fire that powers the <code>z-index</code> property is a concept called <strong>stacking context</strong>. In the next section, we are going to go over the meaning of this term, what it actually means in practice, how it works, and how it relates to <code>z-index</code>.</p>
<p>The stacking context is simply a term we use to define how the browser decides which elements in the DOM come first and which to "render" on top. </p>
<p>When we start writing a block of HTML code, one element after the other, the natural way the browser decides which element comes on top is by checking the order of the DOM elements. See the codepen playground below for more details:</p>
<div class="embed-wrapper">
        <iframe width="100%" height="350" src="https://codepen.io/developeraspire5/embed/eYjavqm" style="aspect-ratio: 16 / 9; width: 100%; height: auto;" title="CodePen embed" scrolling="no" allowtransparency="true" allowfullscreen="true" loading="lazy"></iframe></div>
<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">"green-box"</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">"pink-box"</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">"blue-box"</span>&gt;</span>  <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
</code></pre>
<pre><code class="lang-css"><span class="hljs-selector-tag">div</span>{
  <span class="hljs-attribute">width</span>: <span class="hljs-number">100px</span>;
  <span class="hljs-attribute">height</span>: <span class="hljs-number">100px</span>;
  <span class="hljs-attribute">border</span>: <span class="hljs-number">3px</span> solid;

}

<span class="hljs-selector-class">.green-box</span>{
  <span class="hljs-attribute">background-color</span>: green;
}
<span class="hljs-selector-class">.pink-box</span>{
  <span class="hljs-attribute">background-color</span>: hotpink;
  <span class="hljs-attribute">margin-top</span>: -<span class="hljs-number">30px</span>;
  <span class="hljs-attribute">margin-left</span>: <span class="hljs-number">20px</span>;
}
<span class="hljs-selector-class">.blue-box</span>{
  <span class="hljs-attribute">background-color</span>: blue;
  <span class="hljs-attribute">margin-top</span>: -<span class="hljs-number">30px</span>;
  <span class="hljs-attribute">margin-left</span>: <span class="hljs-number">40px</span>;
}
</code></pre>
<p>From the example above, you can see how the browser stacks DOM elements. It does so by simply checking the DOM order of each element, and rendering the latter element on top of the former element. </p>
<p>Think of it this way – how do you stack books? The last one always appears on top, the first one is always the one at the bottom. When you see some stacked books, you already know that the one at the bottom of the stack was the first book to be added to the stack (it started the stack) and the one on the top of the stack was the last to be added to the stack.</p>
<p>In the example above, the blue box is on top because it is the last on the stack as interpreted by the browser, while the green box is at the bottom of the stack because it is the first element in the DOM order.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/02/stacked-books.jpg" alt="Image" width="600" height="400" loading="lazy">
<em>A pictorial representation of how the browser render DOM elements - shown as stacked books.</em></p>
<p>The process of the browser making the decision about which DOM element to be painted and rendered on top the other element is called the <strong>stacking context.</strong> Let's keep this in mind as we will make reference to this term during the rest of the article.</p>
<p>Whenever a stacking context gets created, it is a memo sent to the browser asking it to re-evaluate the DOM elements and render/stack them accordingly.</p>
<p>Now that we have seen and understood what a stacking context means and how the browser renders DOM elements, let's move to other <code>CSS</code> properties that have the ability to affect how the browser makes these decisions.</p>
<h2 id="heading-positioned-elements-in-css">Positioned Elements in CSS</h2>
<p>There is a rule of thumb I want you to always remember as you go about your daily battles with <code>CSS</code>, especially when working with <code>z-index</code> and the stacking context: <strong>"Positioned elements always come on top"</strong>. </p>
<p>What does this mean? Let's find out below:</p>
<div class="embed-wrapper">
        <iframe width="100%" height="350" src="https://codepen.io/developeraspire5/embed/OJwYmNB" style="aspect-ratio: 16 / 9; width: 100%; height: auto;" title="CodePen embed" scrolling="no" allowtransparency="true" allowfullscreen="true" loading="lazy"></iframe></div>
<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">"green-box"</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">"pink-box"</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">"blue-box"</span>&gt;</span>  <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
</code></pre>
<pre><code class="lang-css"><span class="hljs-selector-tag">div</span>{
  <span class="hljs-attribute">width</span>: <span class="hljs-number">100px</span>;
  <span class="hljs-attribute">height</span>: <span class="hljs-number">100px</span>;
  <span class="hljs-attribute">border</span>: <span class="hljs-number">3px</span> solid;

}

<span class="hljs-selector-class">.green-box</span>{
  <span class="hljs-attribute">background-color</span>: green;
  <span class="hljs-attribute">position</span>: relative;
}
<span class="hljs-selector-class">.pink-box</span>{
  <span class="hljs-attribute">background-color</span>: hotpink;
  <span class="hljs-attribute">margin-top</span>: -<span class="hljs-number">30px</span>;
  <span class="hljs-attribute">margin-left</span>: <span class="hljs-number">20px</span>;
}
<span class="hljs-selector-class">.blue-box</span>{
  <span class="hljs-attribute">background-color</span>: blue;
  <span class="hljs-attribute">margin-top</span>: -<span class="hljs-number">30px</span>;
  <span class="hljs-attribute">margin-left</span>: <span class="hljs-number">40px</span>;

}
</code></pre>
<p>Here it goes! What happened? In the previous Codepen snippet I shared above, we saw how the browser rendered the boxes. Because of thier DOM order, the green box was farther below the stack than it peers. </p>
<p>But now it is on top of the rest. From the result in the Codepen playground, we can clearly see that the green box is being rendered above the pink box. How?</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/02/image-48.png" alt="Image" width="600" height="400" loading="lazy">
<em>The green box being rendered on top of the rest of the other elements</em></p>
<p>Just like the rule of thumb clearly stated, setting the position property on any element in the DOM tells the browser to kindly re-do its calculations. Then, after those calculations, the browser decided to render the DOM element with the position property on top of any other elements regardless of their DOM order.</p>
<p>It is also worth mentioning that no matter the number of the <code>z-index</code> value we add for the other elements, they will never come on top of a positioned element. Yeah! I know you just had that euphoric revelation moment of "So this was the cause of my bug the other day at work". </p>
<p>You can play around with the playground by adding a <code>z-index</code> property to the other elements and adding a large value and see the result – take it up to 500 even. I assure you none of those elements will get placed on top of the positioned element.</p>
<p><strong>Note:</strong> This doesn't apply to <code>position: static</code>. This is because <code>position: static</code> is the default positioned value assigned by <code>CSS</code> to all DOM elements. You can check it out by editing the playground above to have <code>position: static</code>.</p>
<p>You are probably thinking, "oh well, what if more than one element has the <code>position</code> property set. If you face this scenario, who wins the stacking context war?".</p>
<p>First I would like you to try it out. Try editing the playground above and setting the position properties on the two other elements.</p>
<p>When this happens, we have just evened all the elements by setting a <code>position</code> property. When the browser sees this, it returns to its default way of stacking these elements by following their DOM order. So it again renders the latter over the former just like how we stack up books. Check out the code snippet below to get a proper understanding.</p>
<div class="embed-wrapper">
        <iframe width="100%" height="350" src="https://codepen.io/developeraspire5/embed/oNMRwbQ" style="aspect-ratio: 16 / 9; width: 100%; height: auto;" title="CodePen embed" scrolling="no" allowtransparency="true" allowfullscreen="true" loading="lazy"></iframe></div>
<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">"green-box"</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">"pink-box"</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">"blue-box"</span>&gt;</span>  <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
</code></pre>
<pre><code class="lang-css"><span class="hljs-selector-tag">div</span>{
  <span class="hljs-attribute">width</span>: <span class="hljs-number">100px</span>;
  <span class="hljs-attribute">height</span>: <span class="hljs-number">100px</span>;
  <span class="hljs-attribute">border</span>: <span class="hljs-number">3px</span> solid;

}

<span class="hljs-selector-class">.green-box</span>{
  <span class="hljs-attribute">background-color</span>: green;
  <span class="hljs-attribute">position</span>: relative;
}
<span class="hljs-selector-class">.pink-box</span>{
  <span class="hljs-attribute">background-color</span>: hotpink;
  <span class="hljs-attribute">margin-top</span>: -<span class="hljs-number">30px</span>;
  <span class="hljs-attribute">margin-left</span>: <span class="hljs-number">20px</span>;
  <span class="hljs-attribute">position</span>: relative;
}
<span class="hljs-selector-class">.blue-box</span>{
  <span class="hljs-attribute">background-color</span>: blue;
  <span class="hljs-attribute">margin-top</span>: -<span class="hljs-number">30px</span>;
  <span class="hljs-attribute">margin-left</span>: <span class="hljs-number">40px</span>;
  <span class="hljs-attribute">position</span>: relative;

}
</code></pre>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/02/image-49.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>This is how stacking context works in the browser. Adopting this mental model is one of the fundamental ways of truly understanding how <code>z-index</code> works.</p>
<p>From the explanations above and the code snippets we saw, you might be wondering: if the <code>z-index</code> won't work when we try to use it when sibling elements have the <code>position</code> property set, how then do we even use it? </p>
<p>Well, what we just experienced is how the browser decides stacking context by default. <code>z-index</code> is simply a property that allows us to override this default value.</p>
<p>But that comes with some rules of its own. We'll explore this in the section below.</p>
<h2 id="heading-how-to-use-the-z-index-property">How to Use the Z-index Property</h2>
<p>If we are looking to change how things work and opt-out from the default way of how the browser renders and stacks DOM elements, <code>CSS</code> has provided us with a property called <code>z-index</code>. And we can use it to achieve this.</p>
<p>First let's demisfity the almighty <code>z-index</code> property: </p>
<p>The <code>z</code> in <code>z-index</code> refers to the <code>z-axis</code>. <code>z-axis</code> represents the 3 dimensional part of an element.</p>
<ul>
<li><code>x-axis</code> is left and right</li>
<li><code>y-axis</code> is up and down</li>
<li><code>z-axis</code> is forward and backward</li>
</ul>
<p>The mental model is that <code>z-index</code> works like 3D – elements with a higher <code>z-index</code> are elevated and pushed closer to a user's view in the browser so that it looks like they are over/in front of the rest of the other elements. </p>
<p>This is the same way 3D billboards work, by pushing images closer to us optically so that if feels almost as if the characters in these billboards are jumping out of the screen. The <code>z-index</code> shares the same concept with a 3D billboard.</p>
<p>Just like every other CSS property with default values, the default value for the <code>z-index</code> property is <code>auto</code>, which can be interpreted as <code>zero</code>. </p>
<p>When we are using <code>z-index</code> on any DOM element, adding a value of 1 or above is a direct command/signal that tells the browser to push that particular DOM element so that it sits right in front of its siblings.</p>
<p>For us to be able to use <code>z-index</code> effectively, there are some rules guiding how it works. Understanding and properly digesting how these rules apply is very important as it takes you one step closer to being free from the <code>z-index</code> struggle and uneccassary bugs. Check out the code snippet below:</p>
<div class="embed-wrapper">
        <iframe width="100%" height="350" src="https://codepen.io/developeraspire5/embed/PoBvjOP" style="aspect-ratio: 16 / 9; width: 100%; height: auto;" title="CodePen embed" scrolling="no" allowtransparency="true" allowfullscreen="true" loading="lazy"></iframe></div>
<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">"green-box"</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">"pink-box"</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">"blue-box"</span>&gt;</span>  <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
</code></pre>
<pre><code class="lang-css"><span class="hljs-selector-tag">div</span>{
  <span class="hljs-attribute">width</span>: <span class="hljs-number">100px</span>;
  <span class="hljs-attribute">height</span>: <span class="hljs-number">100px</span>;
  <span class="hljs-attribute">border</span>: <span class="hljs-number">3px</span> solid;

}

<span class="hljs-selector-class">.green-box</span>{
  <span class="hljs-attribute">background-color</span>: green;
  <span class="hljs-attribute">z-index</span>: <span class="hljs-number">6</span>;
}

<span class="hljs-selector-class">.pink-box</span>{
  <span class="hljs-attribute">background-color</span>: hotpink;
  <span class="hljs-attribute">margin-top</span>: -<span class="hljs-number">30px</span>;
  <span class="hljs-attribute">margin-left</span>: <span class="hljs-number">20px</span>;
}
<span class="hljs-selector-class">.blue-box</span>{
  <span class="hljs-attribute">background-color</span>: blue;
  <span class="hljs-attribute">margin-top</span>: -<span class="hljs-number">30px</span>;
  <span class="hljs-attribute">margin-left</span>: <span class="hljs-number">40px</span>;
}
</code></pre>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/02/image-52.png" alt="Image" width="600" height="400" loading="lazy">
<em>Even after adding a big z-index value to the green box it still doesn't comes on top the pink box</em></p>
<p>Isn't it surprising that, after setting a <code>z-index</code> value of <code>6</code> (a relatively big number for <code>z-index</code>), stacking context doesn't change? </p>
<p>The expectation after doing this is to see the green box being rendered on top of the rest the the boxes (since of course we know that <code>z-index</code> is used to get one element to be on top of the rest).</p>
<p>But in this case it is not working. Moments like this will lead to endless frustration and pulling out of hair and the rhetorical question: "Why aren't you not working?" and eventually a bad day at work. </p>
<p>I introduce you to the first rule of z-index:</p>
<h3 id="heading-z-index-only-works-with-positioned-elements"><code>z-index</code> only works with positioned elements.</h3>
<p>Now, I want you to go edit the playground and set <code>position: relative</code> on the green box and see the result. Try it by editing the Codepen playground above.</p>
<p>If you did, you will immediately see that the green box is now being rendered on top and the browser has re-calculated the stacking context and rendered the DOM elements accordingly via the new information it received. Always remember this first rule. See the first rule in action below:</p>
<div class="embed-wrapper">
        <iframe width="100%" height="350" src="https://codepen.io/developeraspire5/embed/LYBoLrv" style="aspect-ratio: 16 / 9; width: 100%; height: auto;" title="CodePen embed" scrolling="no" allowtransparency="true" allowfullscreen="true" loading="lazy"></iframe></div>
<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">"green-box"</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">"pink-box"</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">"blue-box"</span>&gt;</span>  <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
</code></pre>
<pre><code class="lang-css"><span class="hljs-selector-tag">div</span>{
  <span class="hljs-attribute">width</span>: <span class="hljs-number">100px</span>;
  <span class="hljs-attribute">height</span>: <span class="hljs-number">100px</span>;
  <span class="hljs-attribute">border</span>: <span class="hljs-number">3px</span> solid;

}

<span class="hljs-selector-class">.green-box</span>{
  <span class="hljs-attribute">background-color</span>: green;
  <span class="hljs-attribute">z-index</span>: <span class="hljs-number">6</span>;
  <span class="hljs-attribute">position</span>: relative;
}
<span class="hljs-selector-class">.pink-box</span>{
  <span class="hljs-attribute">background-color</span>: hotpink;
  <span class="hljs-attribute">margin-top</span>: -<span class="hljs-number">30px</span>;
  <span class="hljs-attribute">margin-left</span>: <span class="hljs-number">20px</span>;
}
<span class="hljs-selector-class">.blue-box</span>{
  <span class="hljs-attribute">background-color</span>: blue;
  <span class="hljs-attribute">margin-top</span>: -<span class="hljs-number">30px</span>;
  <span class="hljs-attribute">margin-left</span>: <span class="hljs-number">40px</span>;
}
</code></pre>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/02/image-50.png" alt="Image" width="600" height="400" loading="lazy">
<em>After setting a position property on the green box, the z-index now works properly, rendering the green box on top.</em></p>
<p>Next stop is the second rule – but before we go into the details and understand what that rule does, I want to introduce you to a little bug. And I want you to see if you know what is happening and if you can resolve it. </p>
<p>If you can't, don't worry, as I will be explaining it in great detail below.</p>
<div class="embed-wrapper">
        <iframe width="100%" height="350" src="https://codepen.io/developeraspire5/embed/MWBdEXe" style="aspect-ratio: 16 / 9; width: 100%; height: auto;" title="CodePen embed" scrolling="no" allowtransparency="true" allowfullscreen="true" loading="lazy"></iframe></div>
<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">header</span>&gt;</span> This is a 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">p</span>&gt;</span>Hello there I am the main <span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">button</span>&gt;</span> Click me <span class="hljs-tag">&lt;/<span class="hljs-name">button</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">body</span>&gt;</span>
</code></pre>
<pre><code class="lang-css"><span class="hljs-keyword">@import</span> url(<span class="hljs-string">'https://fonts.googleapis.com/css2?family=Mulish:wght@200..900&amp;display=swap'</span>);
<span class="hljs-selector-tag">body</span>{
  <span class="hljs-attribute">font-family</span>: <span class="hljs-string">'Mulish'</span>, sans-serif;

}
<span class="hljs-selector-tag">header</span> {
  <span class="hljs-attribute">background-color</span>: hotpink;
  <span class="hljs-attribute">text-align</span>: center;
  <span class="hljs-attribute">padding</span>: <span class="hljs-number">30px</span>;
  <span class="hljs-attribute">position</span>: relative;
  <span class="hljs-attribute">z-index</span>: <span class="hljs-number">2</span>;
}

<span class="hljs-selector-tag">main</span> {
  <span class="hljs-attribute">text-align</span>: center;
  <span class="hljs-attribute">background-color</span>: blue;
  <span class="hljs-attribute">color</span>: white;
  <span class="hljs-attribute">padding</span>: <span class="hljs-number">30px</span>;
  <span class="hljs-attribute">position</span>: relative;
  <span class="hljs-attribute">z-index</span>: <span class="hljs-number">1</span>;

}
<span class="hljs-selector-tag">button</span> {
  <span class="hljs-attribute">margin</span>: <span class="hljs-number">0</span> auto;
  <span class="hljs-attribute">width</span>: <span class="hljs-number">90px</span>;
  <span class="hljs-attribute">border</span>: none;
  <span class="hljs-attribute">text-align</span>: center;
  <span class="hljs-attribute">padding</span>: <span class="hljs-number">8px</span>;
  <span class="hljs-attribute">background</span>: white;
  <span class="hljs-attribute">box-shadow</span>: <span class="hljs-number">1px</span> <span class="hljs-number">2px</span> <span class="hljs-number">8px</span> <span class="hljs-built_in">hsl</span>(<span class="hljs-number">0deg</span> <span class="hljs-number">0%</span> <span class="hljs-number">0%</span> / <span class="hljs-number">0.25</span>);
  <span class="hljs-attribute">border-radius</span>: <span class="hljs-number">6px</span>;

  <span class="hljs-attribute">position</span>: absolute;
  <span class="hljs-attribute">z-index</span>: <span class="hljs-number">999999</span>;
  <span class="hljs-attribute">top</span>: -<span class="hljs-number">12px</span>;
}
</code></pre>
<p>From the code snippet above, we have seen yet another <code>z-index</code> issue that can lead to hours of debugging without even knowing what is wrong. </p>
<p>Going through the code, we can see that the <code>button</code> has a outrageous number as its <code>z-index</code> value, and yet it is not sitting on top of the header. This might make you take a step back and reflect on the first rule of <code>z-index</code> and say "But it is a positioned element, why is it not working?".</p>
<p>That brings us to the second rule of <code>z-index</code>:</p>
<h3 id="heading-a-z-index-property-in-an-isolated-stacking-context-is-not-regarded-outside-the-isolated-stacking-context">A <code>z-index</code> property in an Isolated stacking context is not regarded outside the Isolated stacking context.</h3>
<p>What does this mean? Let me break it down:</p>
<p>From the code above, we can see that the <code>main</code> has a <code>position</code> property and also a <code>z-index</code> property. The same thing applies to the <code>header</code> element – the browser has used this value and calculated the stacking context. Since the <code>header</code> has a higher <code>z-index</code> value, it rendered it on top. As simple as that.</p>
<p>Now, the <code>button</code> is a child of  <code>main</code> that also has the <code>position</code> property set. It also a <code>z-index</code> set to even a higher number. </p>
<p>In reference to the second rule, since <code>main</code> has the <code>z-index</code> property which creates something called an <strong>isolated stacking context</strong>, the <code>button</code> element is not regarded when the browser tries to work up the new stacking context.</p>
<p>You can go ahead and remove the <code>z-index</code> property on the <code>main</code> element and see what happens.</p>
<p>If you did that, you likely saw that immediately the <code>button</code> was rendered on top of the <code>header</code> element. </p>
<p>This might be pretty confusing at first, but trust me – when you use it and pratice more with it, it'll stick. I have an analogy to help you create a mental model when you think of this second rule:</p>
<h3 id="heading-captain-analogy">Captain analogy</h3>
<p>In a plane, there are usually 2 pilots, both of whom are equally qualified to fly and captain an airplane. But only one of those 2 pilots are actually chosen to be the captain of that specific flight. As long as the chosen pilot is not missing, sick, or injured during the course of the flight, there is no need for the second pilot to assume being a captain. </p>
<p>But in a situation where something bad happens to the chosen pilot, the second pilot is allowed and mandated to be captain.</p>
<p>Use this same analogy on the <code>main</code> and <code>button</code>, <code>main</code> has already been assigned a captain by having the <code>z-index</code> property. Because of this, the <code>z-index</code> property of the <code>button</code> becomes useless not matter how big we bump up the numbers.</p>
<p>But once we take away the <code>z-index</code> property from the <code>main</code> , the <code>button</code> is now free to be the captain.</p>
<p>Incase you have forgotten what a stacking context means:</p>
<blockquote>
<p>The stacking context is simply a term used to define how the browser decides which elements in the DOM comes first and which to "render" on top.</p>
</blockquote>
<p>We have discussed extensively how stacking context works and how it's created, but below is a summary:</p>
<ul>
<li>Setting a position property (relative, fixed or absolute) on a DOM element.</li>
<li>Setting the <code>z-index</code> property on a DOM element.</li>
<li>Setting <code>opacity</code> to a value less than <code>1</code>.</li>
<li>Using the <code>isolation</code> property.</li>
<li>Using the <code>transform</code>, <code>filter</code>, <code>clip-path</code>, or <code>perspective</code> CSS properties.</li>
</ul>
<p>This simply means that using any of the properties above tells the browser to calculate and see which DOM element should be rendered on top of the rest of the elements.</p>
<p>You can read more about how stacking context works <a target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Positioning/Understanding_z_index/The_stacking_context">on the MDN</a>.</p>
<h2 id="heading-how-to-debug-the-z-index">How to Debug the Z-Index</h2>
<p>Before we wrap up this article, I want to introduce you to a new <code>property</code> that you can use alongside the <code>z-index</code> property. It helps you deal with stacking contexts in a more pleasant way.</p>
<p>I will do so by introducing a bug so we can see how to fix it. Check the codepen playground below to see:</p>
<div class="embed-wrapper">
        <iframe width="100%" height="350" src="https://codepen.io/developeraspire5/embed/ZEjNaav" style="aspect-ratio: 16 / 9; width: 100%; height: auto;" title="CodePen embed" scrolling="no" allowtransparency="true" allowfullscreen="true" loading="lazy"></iframe></div>
<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">header</span>&gt;</span> This is a 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">button</span>&gt;</span> Click here to suscribe <span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>Hello there I am the main <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.   Reiciendis numquam sapiente veniam fugiat. Harum voluptatum est ab similique incidunt,Quae, amet rem. Minima vitae, accusantium corrupti dolorem perferendis qui magnam...[view the full code snippet on the codepen playground above<span class="hljs-tag">&lt;/<span class="hljs-name">p</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">body</span>&gt;</span>
</code></pre>
<pre><code class="lang-css"><span class="hljs-keyword">@import</span> url(<span class="hljs-string">'https://fonts.googleapis.com/css2?family=Mulish:wght@200..900&amp;display=swap'</span>);
<span class="hljs-selector-tag">body</span>{
  <span class="hljs-attribute">font-family</span>: <span class="hljs-string">'Mulish'</span>, sans-serif;

}
<span class="hljs-selector-tag">header</span> {
  <span class="hljs-attribute">background-color</span>: hotpink;
  <span class="hljs-attribute">text-align</span>: center;
  <span class="hljs-attribute">padding</span>: <span class="hljs-number">30px</span>;
  <span class="hljs-attribute">position</span>: sticky;
  <span class="hljs-attribute">top</span>: <span class="hljs-number">0</span>;
  <span class="hljs-attribute">z-index</span>: <span class="hljs-number">2</span>;
}

<span class="hljs-selector-tag">main</span> {
  <span class="hljs-attribute">text-align</span>: center;
  <span class="hljs-attribute">background-color</span>: blue;
  <span class="hljs-attribute">color</span>: white;
  <span class="hljs-attribute">padding</span>: <span class="hljs-number">30px</span>;
  <span class="hljs-attribute">position</span>: relative;
  <span class="hljs-attribute">min-height</span>: <span class="hljs-number">100vh</span>;
}
<span class="hljs-selector-tag">button</span> {
  <span class="hljs-attribute">border</span>: none;
  <span class="hljs-attribute">text-align</span>: center;
  <span class="hljs-attribute">padding</span>: <span class="hljs-number">8px</span>;
  <span class="hljs-attribute">background</span>: white;
  <span class="hljs-attribute">box-shadow</span>: <span class="hljs-number">1px</span> <span class="hljs-number">2px</span> <span class="hljs-number">8px</span> <span class="hljs-built_in">hsl</span>(<span class="hljs-number">0deg</span> <span class="hljs-number">0%</span> <span class="hljs-number">0%</span> / <span class="hljs-number">0.25</span>);
  <span class="hljs-attribute">border-radius</span>: <span class="hljs-number">6px</span>;

  <span class="hljs-attribute">position</span>: sticky;
  <span class="hljs-attribute">top</span>: <span class="hljs-number">0</span>;
  <span class="hljs-attribute">right</span>: <span class="hljs-number">20px</span>;
  <span class="hljs-attribute">margin-left</span>: <span class="hljs-number">100rem</span>;
  <span class="hljs-attribute">z-index</span>: <span class="hljs-number">2</span>;  
}
</code></pre>
<p>If you run the playground above and see the result you will notice an issue there. Here is what I'm trying to do:</p>
<p>We have a blog, and in every blog post we want a floating sticky button that says "Click here to subscribe" because of course we want more viewers subscribed to the blog. </p>
<p>We do this by adding the <code>position: sticky</code> on the button so that it is always floating and in view as the users read the blog post. Once they see it enough, maybe they'll decide to subscribe.</p>
<p>We also want this button to be adherent to the blog post itself, which means as soon as the blog post is no longer in view, there is no reason why the button should be there. Because of this, we made the button a child of the <code>main</code> element which contains the blog post. </p>
<p>While this is true, we also want the button to be above/in front of the content of the blog post, simply floating on top the posts' text. To do this we added a <code>z-index</code> property. Now, because we already have a <code>position</code> property, we were very confident that the button would be stacked on top of the content by the browser.</p>
<p>From the page, we also added a sticky <code>header</code>, so that the <code>header</code> is glued to the page and never scrolls away. We also want the <code>header</code> to be on top on the other elements, so the blog post and any other preceding DOM elements just slip under the header.</p>
<p>To accomplish this, we add a <code>z-index</code> value of <code>2</code> so it is pushed further up the stack and closer to the screen which renders it on top of the other DOM elements.</p>
<p>After doing this and feeling satisfied with our work, we notice that we have a bug (I hate bugs): the button is simply not doing what we want it do. </p>
<p>The button is actually going above the <code>header</code> instead of going below alongside the blog post as we intended. </p>
<p>This is a recipe for further frustration that causes quite a bit of pulling and screaming at the computer screen along with "Why is CSS so difficult?".</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/02/image-44.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Try going over the code and figuring out what the issue really is. Then come back to this article and we will solve it together.</p>
<p>Remember our second rule of <code>z-index</code>? Where we used the Captain analogy to describe how stacking contexts are compared? That is what is playing out here.</p>
<p>Looking at the code, we can see that we created 2 stacking contexts:</p>
<ul>
<li>When we used the <code>positioned</code> and <code>z-index</code> on the <code>header</code> element.</li>
<li>When we used the <code>positioned</code> and <code>z-index</code> on the <code>button</code> element.</li>
</ul>
<p>From the points above we can see that these two elements are the ones being compared by the browser in order to create the correct stacking context.</p>
<p>Also remember we discussed that:</p>
<blockquote>
<p>If two DOM elements have the exact same properties for creating a stacking context, the browser decides which comes out on top by following the DOM order. This means that the latter element comes on top of the former, just like in a stack of books.</p>
</blockquote>
<p>That is how the browser decided that <code>button</code> has has to come on top. When we compare alongside the browser, we see that:</p>
<ul>
<li>The <code>header</code> has <code>position: sticky</code>, but the <code>button</code> also has <code>position: sticky</code>. It doesn't matter which value is used as long as the element is using a <code>position</code> property.</li>
<li>The header has a <code>z-index</code> of 2 (because it wants to come on top), and the button also has a <code>z-index</code> of 2 (because it wants to be above the content of the blog).</li>
</ul>
<p>This has left the browser with no other choice than to decide the winner by following the DOM order, which means that since <code>button</code> is the latter in the DOM order it will come on top of the <code>header</code>. Phew! What a bug.</p>
<p>How do we solve this? We can go back to our Captain analogy:</p>
<blockquote>
<p>On a plane, there are 2 pilots, both of them are equally qualified to fly and captain the plane. But only one of those 2 pilots are actually chosen to be the captain for that flight. As long as the chosen pilot is not missing, sick, or injured, there is no need for the second pilot to assume being a captain.   </p>
<p>But in a situation where something bad happens to the chosen pilot, the second pilot is allowed and mandated to be captain.</p>
</blockquote>
<p>Remember that <code>button</code> is a child of <code>main</code> but the <code>main</code> has no <code>z-index</code>. This means it is not a captain, which also means there is no <strong>isolated stacking context</strong> hindering the <code>button</code>'s <code>z-index</code> property from being disregarded. Instead, the browser will consider it and compare it with the <code>header</code> element to decide which element should be rendered on top.</p>
<p>We can resolve this by applying the second rule of <code>z-index</code> by simply creating an <strong>isolated stacking</strong> context. We do this by adding a <code>z-index</code> property and also setting a <code>position</code> property on the <code>main</code> element.  Let's see this in the code snippet below:</p>
<div class="embed-wrapper">
        <iframe width="100%" height="350" src="https://codepen.io/developeraspire5/embed/yLqWpEZ" style="aspect-ratio: 16 / 9; width: 100%; height: auto;" title="CodePen embed" scrolling="no" allowtransparency="true" allowfullscreen="true" loading="lazy"></iframe></div>
<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">header</span>&gt;</span> This is a 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">button</span>&gt;</span> Click here to suscribe <span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>Hello there I am the main <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.   Reiciendis numquam sapiente veniam fugiat. Harum voluptatum est ab similique incidunt,Quae, amet rem. Minima vitae, accusantium corrupti dolorem perferendis qui magnam...[view the full code snippet on the codepen playground above<span class="hljs-tag">&lt;/<span class="hljs-name">p</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">body</span>&gt;</span>
</code></pre>
<pre><code class="lang-css"><span class="hljs-keyword">@import</span> url(<span class="hljs-string">'https://fonts.googleapis.com/css2?family=Mulish:wght@200..900&amp;display=swap'</span>);
<span class="hljs-selector-tag">body</span>{
  <span class="hljs-attribute">font-family</span>: <span class="hljs-string">'Mulish'</span>, sans-serif;

}
<span class="hljs-selector-tag">header</span> {
  <span class="hljs-attribute">background-color</span>: hotpink;
  <span class="hljs-attribute">text-align</span>: center;
  <span class="hljs-attribute">padding</span>: <span class="hljs-number">30px</span>;
  <span class="hljs-attribute">position</span>: sticky;
  <span class="hljs-attribute">top</span>: <span class="hljs-number">0</span>;
  <span class="hljs-attribute">z-index</span>: <span class="hljs-number">2</span>;
}

<span class="hljs-selector-tag">main</span> {
  <span class="hljs-attribute">text-align</span>: center;
  <span class="hljs-attribute">background-color</span>: blue;
  <span class="hljs-attribute">color</span>: white;
  <span class="hljs-attribute">padding</span>: <span class="hljs-number">30px</span>;
  <span class="hljs-attribute">position</span>: relative;
  <span class="hljs-attribute">min-height</span>: <span class="hljs-number">100vh</span>;
  <span class="hljs-attribute">position</span>: relative;
  <span class="hljs-attribute">z-index</span>: <span class="hljs-number">1</span>;
}
<span class="hljs-selector-tag">button</span> {
  <span class="hljs-attribute">border</span>: none;
  <span class="hljs-attribute">text-align</span>: center;
  <span class="hljs-attribute">padding</span>: <span class="hljs-number">8px</span>;
  <span class="hljs-attribute">background</span>: white;
  <span class="hljs-attribute">box-shadow</span>: <span class="hljs-number">1px</span> <span class="hljs-number">2px</span> <span class="hljs-number">8px</span> <span class="hljs-built_in">hsl</span>(<span class="hljs-number">0deg</span> <span class="hljs-number">0%</span> <span class="hljs-number">0%</span> / <span class="hljs-number">0.25</span>);
  <span class="hljs-attribute">border-radius</span>: <span class="hljs-number">6px</span>;

  <span class="hljs-attribute">position</span>: sticky;
  <span class="hljs-attribute">top</span>: <span class="hljs-number">0</span>;
  <span class="hljs-attribute">right</span>: <span class="hljs-number">20px</span>;
  <span class="hljs-attribute">margin-left</span>: <span class="hljs-number">100rem</span>;
  <span class="hljs-attribute">z-index</span>: <span class="hljs-number">2</span>;  
}
</code></pre>
<p>Tada! Solved.</p>
<p>Now we have handed the captain mantle to <code>main</code> who is a parent to the <code>button</code>. This forces the <code>button</code> to step aside. And since the <code>z-index</code> on the <code>header</code> is <code>2</code> (which is a bigger number than <code>1</code> which we set on the <code>main</code>), the <code>button</code> is now going under the header alongside the blog post. </p>
<p>This is because, just like the second rule of <code>z-index</code> explained, the <code>z-index</code> value on the <code>button</code> no longer has any effect on the stacking context decision made by the browser.</p>
<p>Here are the 2 rules of the <code>z-index</code> property again:</p>
<ol>
<li><strong><code>z-index</code> only works with positioned elements.</strong></li>
<li><strong>A <code>z-index</code> property in an isolated stacking context is not regarded outside the isolated stacking context.</strong></li>
</ol>
<h3 id="heading-how-to-use-the-isolation-property">How to use the isolation property</h3>
<p>While the above code clearly solved our problem, we are still left with something every developer hates – that is, having littered <code>z-index</code> all over our codebase, we can go on vacation for a month, come back to our codebase, and encounter yet another <code>z-index</code> bug. We might forget what some particular <code>z-index</code> value was even supposed to do. Then we'll remove it which will plunge ourselves into another endless round of bug fighting.</p>
<p>Instead of using <code>position: relative; z-index: 1;</code> on our <code>main</code> element to create the <strong>isolated stacking context</strong>, we can simply do this instead:   </p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/02/image-46.png" alt="Image" width="600" height="400" loading="lazy">
<em>Using the isolation property to solve the bug</em></p>
<pre><code class="lang-css"><span class="hljs-selector-tag">main</span> {
  <span class="hljs-attribute">isolation</span>: isolate;
}
</code></pre>
<p>The <code>isolation</code> property does only one thing which is: it creates a stacking context.</p>
<p>This is the simplest way to create a stacking context. It can be useful when you want to prevent the <code>z-index</code> values of child elements from affecting the layout of a webpage (except, of course, when we want it to do so). This property allows us achieve this without the burden of having the <code>z-index</code> every where in our code.</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>We have reached the end of this article. Hopefully you now understand the underlying mechanism behind how the browser stacks elements in the DOM (called a stacking context). You should also know how the <code>z-index</code> propery works, <code>z-index</code> rules, how to effectively use these rules.</p>
<p>I hope you learned a lot from this article, and I am looking forward to seeing you win every <code>z-index</code> battle you might face in future. You can always come back to this post and read it again.</p>
<p>For more CSS tips, follow me on <a target="_blank" href="https://twitter.com/developeraspire">Twitter</a>.</p>
<p>Thanks for reading! See you next time.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Make a Custom Mouse Cursor with CSS and JavaScript ]]>
                </title>
                <description>
                    <![CDATA[ Have you ever visited a website and been totally blown away by its amazing features? One of them might be a cool mouse cursor that is different from the regular arrow or pointer cursors you are used to.   This can really improve user experience, and ... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-make-a-custom-mouse-cursor-with-css-and-javascript/</link>
                <guid isPermaLink="false">66ba5971e30fab558579a14b</guid>
                
                    <category>
                        <![CDATA[ CSS ]]>
                    </category>
                
                    <category>
                        <![CDATA[ JavaScript ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Franklin Okolie ]]>
                </dc:creator>
                <pubDate>Mon, 10 Jan 2022 16:13:35 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2022/01/salman-hossain-saif-m3xjTe9zl6k-unsplash.jpg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Have you ever visited a website and been totally blown away by its amazing features? One of them might be a cool mouse cursor that is different from the regular arrow or pointer cursors you are used to.  </p>
<p>This can really improve user experience, and lately I've been wondering how it works. So I started to do some research and I found out how it is done.</p>
<p>In this article, I will be explaining how to make a custom mouse cursor. By the end of this article you will learn how to make these cursors with two different methods, using CSS and JavaScript. Then you be will ready to vamp up your website with different creative cursors to keep your audience engaged. Ready? Let's dive in.</p>
<h2 id="heading-prerequisites">Prerequisites</h2>
<p>This article is beginner-friendly, but to understand some concepts you should have basic knowledge of:</p>
<ul>
<li>HTML</li>
<li>Basic CSS</li>
<li>Basic JavaScript</li>
</ul>
<h2 id="heading-how-to-customize-a-mouse-cursor-with-css">How to Customize a Mouse Cursor with CSS</h2>
<p>Customizing a mouse cursor with CSS is pretty simple, as CSS already has a property to handle this. All we need to do is identify this property and use it. </p>
<p>As Frontend Engineers we use this property often – it is none other than the almighty <code>cursor</code> property. Yes, that property is what gives us the power to make a custom cursor of our choice.</p>
<p>Before we go to a practical example, let's look at the values associated with the CSS <code>cursor</code> property. While most developers just use a few important ones, there are more we should look at.</p>
<div class="embed-wrapper">
        <iframe width="100%" height="350" src="https://codepen.io/developeraspire5/embed/XWeBEXo" style="aspect-ratio: 16 / 9; width: 100%; height: auto;" title="CodePen embed" scrolling="no" allowtransparency="true" allowfullscreen="true" loading="lazy"></iframe></div>
<p>From the above code snippet and from the results, you can see and test out different mouse cursors that CSS has by hovering your mouse cursor on each of those boxes containing the name of each CSS <code>cursor</code> property value.</p>
<p>Now how do I use CSS to customize a mouse cursor? To use this, you just have to tell CSS what image you intend to use and point the cursor property to the image URL using the <code>url</code> value.</p>
<pre><code class="lang-css"><span class="hljs-selector-tag">body</span> {
  <span class="hljs-attribute">cursor</span>: <span class="hljs-built_in">url</span>(<span class="hljs-string">'image-path.png'</span>),auto;
}
</code></pre>
<p>From the code snippet above, you can see I set this on the document body, so it can apply to the cursor no matter where it moves. It has the image specified in <code>url()</code>.</p>
<p>The next value of the property is a fallback, just in case the image doesn't load or can not be found maybe due to some internal glitches. I'm sure you wouldn't want your website to be "cursor-less", so adding a fallback is very important. You can also add as many fallback URLs as you can or want.</p>
<pre><code class="lang-css"><span class="hljs-selector-tag">body</span> {
  <span class="hljs-attribute">cursor</span>: <span class="hljs-built_in">url</span>(<span class="hljs-string">'image-path.png'</span>), <span class="hljs-built_in">url</span>(<span class="hljs-string">'image-path-2.svg), 
          url('</span>image-path-<span class="hljs-number">3</span>.jpeg<span class="hljs-string">'), auto;
}</span>
</code></pre>
<p>You can also customize the cursor on a particular element or section of your webpage. Below is a CodePen example:</p>
<div class="embed-wrapper">
        <iframe width="100%" height="350" src="https://codepen.io/developeraspire5/embed/GRMBxWN" style="aspect-ratio: 16 / 9; width: 100%; height: auto;" title="CodePen embed" scrolling="no" allowtransparency="true" allowfullscreen="true" loading="lazy"></iframe></div>
<p>That is all there is to customizing cursors in CSS. Now let's see how we can do this is JavaScript.</p>
<h2 id="heading-how-to-make-custom-mouse-cursors-with-javascript">How to Make Custom Mouse Cursors with JavaScript</h2>
<p>To make this happen with JavaScript, you need to manipulate the DOM to get the desired result. </p>
<p>First, let's see the HTML:</p>
<h3 id="heading-the-html">The HTML</h3>
<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">"cursor rounded"</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">"cursor pointed"</span>&gt;</span><span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>
</code></pre>
<p>From the code snippet above, I created two <code>divs</code> to represent the cursor. The plan is to manipulate these divs from JavaScript so their movement over the webpage is scrolled by the JavaScript <code>mousemove</code> event using the X and Y coordinates of the mouse movement. </p>
<p>Now let's get to the CSS part which will all make sense piece by piece.</p>
<h3 id="heading-how-to-style-custom-cursors-with-css">How to style custom cursors with CSS</h3>
<pre><code class="lang-css"><span class="hljs-selector-tag">body</span>{
  <span class="hljs-attribute">background-color</span>: <span class="hljs-number">#1D1E22</span>;
  <span class="hljs-attribute">cursor</span>: none;
}

<span class="hljs-selector-class">.rounded</span>{
  <span class="hljs-attribute">width</span>: <span class="hljs-number">30px</span>;
  <span class="hljs-attribute">height</span>: <span class="hljs-number">30px</span>;
  <span class="hljs-attribute">border</span>: <span class="hljs-number">2px</span> solid <span class="hljs-number">#fff</span>;
  <span class="hljs-attribute">border-radius</span>: <span class="hljs-number">50%</span>;
}

<span class="hljs-selector-class">.pointed</span>{
  <span class="hljs-attribute">width</span>: <span class="hljs-number">7px</span>;
  <span class="hljs-attribute">height</span>: <span class="hljs-number">7px</span>;
  <span class="hljs-attribute">background-color</span>: white;
  <span class="hljs-attribute">border-radius</span>: <span class="hljs-number">50%</span>;
}
</code></pre>
<p>Taking a look at the CSS code above, I disabled the cursor (remember <code>cursor:none</code>?). This will make the cursor go invisible, allowing our custom cursor only to display. </p>
<p>The <code>divs</code> I styled to give them a unique "cursor-like" look. You can absolutely do more with it, maybe add a background image, emoji, stickers and so on provided there are images. Now, let's take a look at the JavaScript</p>
<h3 id="heading-how-to-use-javascript-to-make-the-cursor-move">How to use JavaScript to make the cursor move</h3>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> cursorRounded = <span class="hljs-built_in">document</span>.querySelector(<span class="hljs-string">'.rounded'</span>);
<span class="hljs-keyword">const</span> cursorPointed = <span class="hljs-built_in">document</span>.querySelector(<span class="hljs-string">'.pointed'</span>);


<span class="hljs-keyword">const</span> moveCursor = <span class="hljs-function">(<span class="hljs-params">e</span>)=&gt;</span> {
  <span class="hljs-keyword">const</span> mouseY = e.clientY;
  <span class="hljs-keyword">const</span> mouseX = e.clientX;

  cursorRounded.style.transform = <span class="hljs-string">`translate3d(<span class="hljs-subst">${mouseX}</span>px, <span class="hljs-subst">${mouseY}</span>px, 0)`</span>;

  cursorPointed.style.transform = <span class="hljs-string">`translate3d(<span class="hljs-subst">${mouseX}</span>px, <span class="hljs-subst">${mouseY}</span>px, 0)`</span>;

}

<span class="hljs-built_in">window</span>.addEventListener(<span class="hljs-string">'mousemove'</span>, moveCursor)
</code></pre>
<p>I added an event listener on the global window object to listen to any mouse movement. When the mouse moves, the <code>moveCursor</code> function expression is called and it receives the event object as a parameter. With this parameter I was able to get the X and Y coordinates on the mouse at any point on the page.</p>
<p>I already selected each kind of cursor from the DOM using JavaScript <code>querySelector</code>. So all I had to do was move them according to the X and Y coordinates of the mouse by controlling the transform properties on the style with the <code>translate3d</code> value. This will enable the divs to move when the mouse moves to any point on the webpage. </p>
<p>And the backticks you see are called template literals. This enables writing variables easily to append them to strings. The alternative would be to concat the variables to the strings.</p>
<p>Simple, right? That's it!</p>
<p>Below is a CodePen sample and result of the above code snippet:</p>
<div class="embed-wrapper">
        <iframe width="100%" height="350" src="https://codepen.io/developeraspire5/embed/gOGjeZG" style="aspect-ratio: 16 / 9; width: 100%; height: auto;" title="CodePen embed" scrolling="no" allowtransparency="true" allowfullscreen="true" loading="lazy"></iframe></div>
<h2 id="heading-which-method-works-best">Which Method Works Best?</h2>
<p>Now it's up to you as the developer to choose which method works best for you. You may choose to use CSS if you want to use some pretty emojis or images as a cursor. On the other hand, you might want to use JavaScript so you can customize complex shapes of your choice and animate the cursor's movement.</p>
<p>Either way is fine, as long as you get your desired results and wow all your site's visitors.</p>
<p>I hope you learnt a lot from this article, an d I am looking forward to seeing what you build with this knowledge. </p>
<p>For more CSS tips, follow me on <a target="_blank" href="https://twitter.com/DeveloperAspire">Twitter</a>.</p>
<p>Thanks for reading, See you next time.</p>
 ]]>
                </content:encoded>
            </item>
        
    </channel>
</rss>
