<?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[ Andrico Karoulla - 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[ Andrico Karoulla - freeCodeCamp.org ]]>
            </title>
            <link>https://www.freecodecamp.org/news/</link>
        </image>
        <generator>Eleventy</generator>
        <lastBuildDate>Sun, 24 May 2026 16:29:53 +0000</lastBuildDate>
        <atom:link href="https://www.freecodecamp.org/news/author/andrico1234/rss.xml" rel="self" type="application/rss+xml" />
        <ttl>60</ttl>
        
            <item>
                <title>
                    <![CDATA[ What is a Component Library? When to Build Your Own and When to Use Someone Else's ]]>
                </title>
                <description>
                    <![CDATA[ If you've built a frontend project in the last five years, you will have likely written some components, and maybe even used a component library. Components and libraries have been an important part of the web development landscape for multiple decad... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/what-is-a-component-library-when-to-build-your-own/</link>
                <guid isPermaLink="false">66bb74b0b66bb7f4d49a11bb</guid>
                
                    <category>
                        <![CDATA[ Web Development ]]>
                    </category>
                
                    <category>
                        <![CDATA[ JavaScript ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Beginner Developers ]]>
                    </category>
                
                    <category>
                        <![CDATA[ component libraries ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Andrico Karoulla ]]>
                </dc:creator>
                <pubDate>Tue, 13 Aug 2024 14:58:56 +0000</pubDate>
                <media:content url="https://cdn.hashnode.com/res/hashnode/image/upload/v1723543483889/400c638b-4a6f-430a-92c3-4d8a7b750464.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>If you've built a frontend project in the last five years, you will have likely written some components, and maybe even used a component library.</p>
<p>Components and libraries have been an important part of the web development landscape for multiple decades now, and they're as useful and as important as ever.</p>
<p>Now, there are going to be times when you should build your own component library, and times when it's better to use a third-party option. By the end of this article, you'll know the benefits and drawbacks of each approach, and you'll be able to make the right call for your next project.</p>
<h3 id="heading-table-of-contents">Table of Contents:</h3>
<ul>
<li><p><a class="post-section-overview" href="#heading-an-analogy-what-if-pre-recorded-music-albums-didnt-exist">An Analogy: What if Pre-Recorded Music Albums Didn't Exist</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-why-im-writing-this-guide">Why I'm Writing this Guide</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-what-is-a-component">What is a Component?</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-what-is-a-component-library">What is a Component Library?</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-whats-the-difference-between-a-component-library-and-a-design-system">What’s the Difference Between a Component Library and a Design System</a></p>
<ul>
<li><p><a class="post-section-overview" href="#heading-design-systems">Design Systems</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-component-libraries">Component Libraries</a></p>
</li>
</ul>
</li>
<li><p><a class="post-section-overview" href="#heading-a-brief-history-of-component-libraries">A Brief History of Component Libraries</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-what-makes-a-good-component-library">What Makes a Good Component Library?</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-what-are-the-benefits-of-using-a-component-library">What Are the Benefits of Using a Component Library?</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-what-are-the-drawbacks-of-using-a-third-party-component-library">What Are the Drawbacks of Using a Third-Party Component Library?</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-the-different-shapes-a-component-library-can-take">The Different Shapes a Component Library Can Take</a></p>
<ul>
<li><p><a class="post-section-overview" href="#heading-utility-classes-libraries-css-style-guides">Utility Classes Libraries / CSS Style Guides</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-off-the-shelf-component-libraries">Off-the-Shelf Component Libraries</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-un-styled-components">Un-styled Components</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-copy-pastable-component-libraries">Copy Pastable Component Libraries</a></p>
</li>
</ul>
</li>
<li><p><a class="post-section-overview" href="#heading-why-isnt-there-one-component-library-to-rule-them-all">Why Isn’t There One Component Library to Rule Them All?</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-should-you-build-your-own-component-library">Should You Build Your Own Component Library?</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-when-and-why-its-useful-to-build-your-own-component-library">When (and Why) It's Useful to Build Your Own Component Library</a></p>
</li>
</ul>
<h2 id="heading-an-analogy-what-if-pre-recorded-music-albums-didnt-exist">An Analogy: What if Pre-Recorded Music Albums Didn't Exist</h2>
<p>I’m a huge music fan. One of my favourite pastimes is to put on a record and listen to it front to back. A music album is simple in concept: it’s a suite of recorded tracks by an artist and is considered a complete and coherent set of songs.</p>
<p>But what if recorded music didn’t exist? Instead of putting songs to tape, CD, or mp3 (or FLAC if you’re that way inclined), you could only listen to an album if the artist played it live for you. You’d need to go to the band, ask them to set up their equipment, and get them to play the album front-to-back. They’d need to play it the same way every time to ensure that everyone had the exact same experience.</p>
<p>The cracks would start to show. It’s not an efficient way to ensure that anyone interested in the band’s music could listen to it. If Taylor Swift were to play her song Fortnight personally for every person who listened to it on Spotify, it would take her 3,179 years. And that doesn’t account for any <a target="_blank" href="https://www.threads.net/@adhd.international/post/C6ugTXAPt71?hl=en-gb">plane travel</a>. Artists would get bored, maybe even careless, leading to a poorer experience for their listeners.</p>
<p>So how does this relate to web development? Every time you build a UI control, you have to ensure it’s functioning, robust, and accessible. You’ll get bored if you keep rewriting the same UI every time. Mistakes will slip through, leading to a bad experience for your end users.</p>
<h2 id="heading-why-im-writing-this-guide">Why I'm Writing this Guide</h2>
<p>I’ve been a web developer for nearly 10 years, and I’ve written hundreds of components, often the same UI pattern many times. I’ve used dozens of component libraries, and have built admin dashboards, component libraries, mobile applications, blogs, Figma plugins, VSCode extensions, and more.</p>
<p>In this article, I'll discuss the role of components and libraries in web development, and whether developers should write their own.</p>
<p>I'm also the creator of <a target="_blank" href="https://component-odyssey.com/">Component Odyssey</a>, a course that'll teach you to build your own component library that works in any frontend framework.</p>
<h2 id="heading-what-is-a-component">What is a Component?</h2>
<p>When building user interfaces, we don’t write all the HTML markup from scratch every single time. We write our UIs using components – reusable building blocks that encapsulate common UI patterns. Writing a component lets you use it multiple times in a single project or even in independent projects.</p>
<p>Here I’ve written a counter component. I’ve written it once and used it in multiple places on the page.</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">body</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"wrapper"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">counter-button</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">counter-button</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">counter-button</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">counter-button</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">counter-button</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">counter-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">script</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"module"</span>&gt;</span><span class="javascript">
    <span class="hljs-keyword">import</span> { LitElement, html } <span class="hljs-keyword">from</span> <span class="hljs-string">'lit'</span>;

    <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">CounterButton</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">LitElement</span> </span>{
      <span class="hljs-keyword">constructor</span>() {
        <span class="hljs-built_in">super</span>();
        <span class="hljs-built_in">this</span>.count = <span class="hljs-number">0</span>;
      }

      <span class="hljs-keyword">static</span> properties = {
        <span class="hljs-attr">count</span>: { <span class="hljs-attr">type</span>: <span class="hljs-built_in">Number</span> }
      };

      _increment() {
        <span class="hljs-built_in">this</span>.count++;
      }

      render() {
        <span class="hljs-keyword">return</span> html`<span class="xml">
          <span class="hljs-tag">&lt;<span class="hljs-name">button</span> @<span class="hljs-attr">click</span>=</span></span><span class="hljs-subst">${<span class="hljs-built_in">this</span>._increment}</span><span class="xml"><span class="hljs-tag">&gt;</span>Count: </span><span class="hljs-subst">${<span class="hljs-built_in">this</span>.count}</span><span class="xml"><span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
        `</span>;
      }
    }

    customElements.define(<span class="hljs-string">'counter-button'</span>, CounterButton);
  </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>We tutorial creators like to demo counters like they’re going out of style – but a real-world application will contain dozens of different UI patterns written as components.</p>
<p>In this article, I’ll group CSS rules that provide styling for certain UI patterns under the components umbrella. The definition can get murky depending on whom you ask.</p>
<h2 id="heading-what-is-a-component-library">What is a Component Library?</h2>
<p>Not all components are standalone. It makes sense for many components to be grouped within a single package, called a component library.</p>
<p>If you want your site to have a specific look or feel, you can use a <em>component library</em>. There are component libraries that:</p>
<ul>
<li><p>offer components that adhere to a design specification.</p>
</li>
<li><p>offer multiple solutions for a specific UI pattern.</p>
</li>
<li><p>work with a specific toolchain</p>
</li>
</ul>
<p>But they come in different shapes and sizes. The definition I’ve come to use when defining a component library is the following:</p>
<p><em>A component library is a set of reusable components that are cohesive in their utility, or appearance (or both). A great component library will help developers achieve their UI needs efficiently, while offering an exemplary experience for the end user.</em></p>
<h2 id="heading-whats-the-difference-between-a-component-library-and-a-design-system">What’s the Difference between a Component Library and a Design System?</h2>
<p>I talk about guidelines and design systems later in this article, so I’ll take a moment to disambiguate them. It can be difficult to see where one ends, one begins, or one subsumes the other.</p>
<h3 id="heading-design-systems"><strong>Design Systems</strong></h3>
<p>I see a design system as a specification for how things should look, feel, and behave. A design system can encompass a product, a brand, or a company to ensure consistency across the suite of experiences. A comprehensive design system will dictate everything from font families, font sizes, and spacing sizes, to UI patterns and copy guidelines.</p>
<p>A few of the most well-known design systems include:</p>
<ul>
<li><p><a target="_blank" href="https://m3.material.io/foundations/layout/understanding-layout/overview">Material Design</a> (Google)</p>
</li>
<li><p><a target="_blank" href="https://base.uber.com/6d2425e9f/p/294ab4-base-design-system">Base Design</a> (Uber)</p>
</li>
<li><p><a target="_blank" href="https://www.lightningdesignsystem.com/getting-started/">Lightning Design System</a> (Salesforce)</p>
</li>
</ul>
<p>While many design systems are specific to companies, there are design systems, like Material Design, that teams across the globe use to shortcut their way to building familiar feeling products. You’ve probably used a handful of products that use Material Design principles, but they’re <a target="_blank" href="https://www.smashingmagazine.com/2021/02/material-design-text-fields/">certainly not free from basic usability issues</a>.</p>
<h3 id="heading-component-libraries"><strong>Component Libraries</strong></h3>
<p>As for component libraries, they may or may not be the code implementation of a design system. If you work for a company with a design system, it’s likely that the corresponding component library (if one exists) is tightly integrated with it.</p>
<p>For instance, Google’s <a target="_blank" href="https://material-web.dev/">Material Web</a> is a web component implementation of Material Design. <a target="_blank" href="https://baseweb.design/components/button/">Base Web</a> and <a target="_blank" href="https://lwc.dev/guide/introduction">Lightning Web Components</a> are also open source.</p>
<h2 id="heading-a-brief-history-of-component-libraries">A Brief History of Component Libraries</h2>
<p>The concept of UI components (or widgets) has been around for a long time. If you want to see a museum’s worth of retro user interfaces, grab some popcorn and watch this <a target="_blank" href="https://vimeo.com/61556918">2+ hour video of "all the widgets" from 1974-1990</a>.</p>
<p>From the early 2000s, we started seeing component libraries made to help developers build for the web.</p>
<p>The web browser landscape back then was unrecognisable from what we see now. Versions of Internet Explorer deviated away from the spec entirely, which was particularly problematic given the <a target="_blank" href="https://en.wikipedia.org/wiki/Usage_share_of_web_browsers#TheCounter.com_(2000_to_2009)">huge market share that IE had back in the day</a>. <a target="_blank" href="https://www.quora.com/Why-do-people-hate-IE6-so-much-and-want-it-to-die#:~:text=IE6%20doesn't%20support%20web,PNGs%20to%20natively%20support%20IE6">Internet Explorer 6 was famously known for being a pain to develop for</a>. This was mainly due to its incorrect implementation of the <a target="_blank" href="https://www.webfx.com/blog/web-design/definitive-guide-to-taming-the-ie6-beast/#616723179a361-3">box model</a>, and lack of CSS2 support.</p>
<blockquote>
<p>💡 TIL, Internet Explorer supported a “<a target="_blank" href="https://www.notion.so/Complete-written-content-806882f918204715a6e45df68f492bdd?pvs=21">quirks mode</a>” that let developers write non-standard HTML and CSS to appease older browsers that didn’t support the standards.</p>
</blockquote>
<p>Fortunately, when I started web development in earnest, many of these issues were ironed out. By this point, there were still a handful of libraries that made writing complex interfaces with cross-browser support a little easier.</p>
<p><a target="_blank" href="https://jqueryui.com/">jQuery UI</a>, the first component library I used, supported accordions and other widgets. But the browser is constantly evolving, and we now have a native way of implementing this accordion pattern using the <code>details</code> and <code>summary</code> elements, available in all browsers in 2020.</p>
<p>With these elements, you can get pretty far along creating interactive accordions without JavaScript.</p>
<p>Contrast this with 2009, before these elements had been implemented in any browser. It required a fair bit of JS to get working. Have a look at the <a target="_blank" href="https://code.jquery.com/ui/1.7.0/jquery-ui.js">jQuery UI v1.7 source code</a>, and CTRL+F “accordion” if you want to see how web devs were implementing accordions 15 years ago.</p>
<p>Over the next couple of decades, the capabilities of the web grew. More powerful devices meant more powerful browsers. More powerful browsers meant web applications became more ambitious.</p>
<p>Developers responded by creating the tools to help us build these applications by allowing us to create UIs using <em>building blocks</em> – that is, a component model. We saw a proliferation of these component-based frameworks. I’m talking Angular, React, and Vue. And each has its own rich ecosystem of component libraries.</p>
<p>There's a reasonable argument to be made that there has been an over-correction and that the frontend landscape is now oversaturated with tools that are too powerful for most people's needs...but let's not go there.</p>
<h2 id="heading-what-makes-a-good-component-library">What Makes a Good Component Library?</h2>
<p>The challenge with building a component library is that they’re not a <em>one-and-done</em> deal. Many of the most popular libraries have been around for years and have had heaps of research, usage feedback, and contributions to get them to where they are now.</p>
<p>I’ve found that a good component library often has the following traits:</p>
<ul>
<li><p>It understands the problems of its target developers and solves those problems well</p>
</li>
<li><p>It has great documentation</p>
</li>
<li><p>It ensures a good experience for the end-user</p>
</li>
<li><p>It’s robust and caters to appropriate input modes and devices.</p>
</li>
</ul>
<p>On the flip side, a way to discern if a component library <em>isn’t good</em> is if it doesn’t consider accessibility, has an inconsistent API, has little to no project stewardship, or has no clear and consistent documentation.</p>
<h2 id="heading-what-are-the-benefits-of-using-a-component-library">What Are the Benefits of Using a Component Library?</h2>
<p>We know what a good component library looks like – so let’s see how one can make your life, and the lives of your users, a little better.</p>
<h3 id="heading-component-libraries-save-you-time">Component Libraries Save You Time</h3>
<p>If you’re on a project with a tight deadline, it’s important to be efficient. But efficiency shouldn’t come at the cost of crafting a robust web experience. Using a component library lets you spend less time reinventing the wheel and more time focusing on the finer details.</p>
<h3 id="heading-component-libraries-make-you-and-your-users-happier">Component Libraries Make You and Your Users Happier</h3>
<p>We’re not motivated by repetitive work. We enjoy technical challenges, and writing the same components over and over again is not a fun challenge. We’ve already spoken about what happens when we get bored and let mistakes slip through.</p>
<p>If you wanted to implement a dialog component from scratch, you’d need to:</p>
<ul>
<li><p>Handle focus trapping correctly</p>
</li>
<li><p>Make the rest of the page inert</p>
</li>
<li><p>Position the dialog correctly</p>
</li>
<li><p>Ensure that it works with assistive technologies</p>
</li>
</ul>
<p>It takes work to remember and implement the above, but the consequence of getting it wrong can render your interface literally unusable. Such is the case if you <a target="_blank" href="https://www.w3.org/WAI/WCAG21/Understanding/no-keyboard-trap.html">incorrectly handle focus</a>.</p>
<p>By using a component library that’s been built with the end users in mind, you can prevent the risk of introducing broken experiences, while spending less time rebuilding the same components.</p>
<h3 id="heading-component-libraries-lead-to-consistent-experiences">Component Libraries Lead to Consistent Experiences</h3>
<p>If you work for a company with several different web applications, they’ll generally follow a set of guidelines. These guidelines might dictate the colour palette to use, the size of your typography, or how UI elements should look and behave.</p>
<p>But you increase the likelihood of your application deviating from the style guide if you’re re-writing components. By having a component library, you can more easily audit your component’s UI against the brand guidelines so they look great, wherever they’re used.</p>
<p>Uber has several different apps that share the same user interface elements. I’m almost certain that they use the same component library across these apps. That way each new app is virtually guaranteed to adhere to the brand’s guidelines.</p>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/4lh0etdq7yhk4zhmiac8.png" alt="Different Uber apps side by side, showing how similar they are in terms of appearance" width="2000" height="1620" loading="lazy"></p>
<h2 id="heading-what-are-the-drawbacks-of-using-a-third-party-component-library">What Are the Drawbacks of Using a Third-Party Component Library?</h2>
<p>The benefits I’ve mentioned above are irrespective of whether you’re using your own component library or a third party. If you or your team has decided that they don’t want to build a library, and instead lean on a third-party, then it’s worth considering the following.</p>
<h3 id="heading-vendor-lock-in">Vendor Lock-in</h3>
<p>By choosing a component library, you’re picking a partner who will greatly impact how you write your frontend code and how your interfaces will look and behave.</p>
<p>The former will have a big impact on you, and the latter will have a big impact on your end users. Using a component library is locking you into the standards of that component library.</p>
<p>The library could introduce massive breaking changes in a major version that could require dedicated development time, and a lot of testing to ensure that no serious regressions were introduced.</p>
<p>A few years back I used React Admin to build a complex admin dashboard to an internal division. The library offered a suite of components specifically dedicated to fetching and displaying complex data.</p>
<p>Because our application at the time relied heavily on React Admin, upgrading between major versions was challenging, especially as many of the internal tools used by React Admin had been swapped out for others. The change surface was huge, and we spent a good deal of time upgrading and flagging the issues that we spotted.</p>
<p>I don’t believe that building our own solution would have saved us any time in the long term, but this kind of vender lock-in is worth considering, especially before going all in on a tool.</p>
<h3 id="heading-code-bloat">Code Bloat</h3>
<p>Shocking as it is, libraries with a lot of components tend to be written using lots of code. Code that you download when installing dependencies, and code you're sending over to your end users.</p>
<p>Modern tooling makes it easier to perform bundle optimisations like tree-shaking to remove unused code, but there’s no guarantee that you’re removing all of the code that your users won’t need.</p>
<p>Unless you dig deep into the libraries that you’re using, you may not be aware of all the separate packages they’re importing. You could end up with hundreds of unnecessary dependencies. The folks in the <a target="_blank" href="https://e18e.dev/">e18e</a> community have been working hard at bringing this problem to light, <a target="_blank" href="https://x.com/DanaWoodman/status/1819084012729798833">while also fixing it too</a>.</p>
<p>Many of these problems could also be said about rolling out your own component library. The biggest difference is that you have stewardship over your component library. You’re able to define how it solves your specific problems, and you have control over improving its shortcomings.</p>
<h2 id="heading-the-different-shapes-a-component-library-can-take">The Different Shapes a Component Library Can Take</h2>
<p>The <a target="_blank" href="https://cds.cern.ch/record/369245/files/dd-89-001.pdf">initial proposal</a> for the World Wide Web was a tool to improve communication between researchers at CERN. The proposal outlined how documents could be shared, and linked to one another through the use of hypertext.</p>
<p>This is the fundamental cornerstone of the web, and we still use the humble <code>&lt;a&gt;</code> tag to link between other HTML documents across the web.</p>
<p>But the web has grown in scope over the last few decades, and the browsers we use to navigate the web have become beasts of their own. The browsers today can enable <a target="_blank" href="https://plumegame.com/">powerful forms of creative expression</a>, and the <a target="_blank" href="https://medium.com/@addyosmani/photoshop-is-now-on-the-web-38d70954365a">running of native-like software</a>.</p>
<p>There are hundreds of different solutions out there, some general purpose, others hyper-niche, but finding the right tool for your next project requires a complex decision process that might look like this:</p>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/bn80olo3e0h8v4h4v311.png" alt="The different kinds of component libraries, and when you should use them. The diagram's context is explored below" width="1536" height="2784" loading="lazy"></p>
<p>This isn’t a comprehensive list of ALL use cases or component library types, but it illustrates how component libraries differ in terms of:</p>
<ul>
<li><p>the technologies involved.</p>
</li>
<li><p>the levels of abstraction they offer.</p>
</li>
<li><p>the problems they solve.</p>
</li>
</ul>
<p>Let’s take a look at some of the most common component library types.</p>
<p>💡 A quick side note: If you're interested in building your own web component library, then consider checking out my course <a target="_blank" href="https://component-odyssey.com/">Component Odyssey</a>. You'll learn how to build and publish a component library that works in any frontend framework.</p>
<h3 id="heading-utility-class-libraries-css-style-guides">Utility Class Libraries / CSS Style Guides</h3>
<p>For me, <a target="_blank" href="https://getbootstrap.com/">Bootstrap</a> is the first that comes to mind. Back in the day, if you wanted to give your site a quick lick of paint, you’d drop the CDN link to the bootstrap CSS file and immediately get that Bootstrap look. It was everywhere in the mid-2010s.</p>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/7zl86ek2nhsoxc043pnt.png" alt="A demo example of a Bootstrap web, circa 2013" width="2784" height="1640" loading="lazy"></p>
<p>The technical scope of these kind of tools range from</p>
<ul>
<li>A single CSS file (<a target="_blank" href="https://picocss.com/">Pico</a>)</li>
</ul>
<p>to</p>
<ul>
<li>A toolchain to generate CSS classes based on your configuration (<a target="_blank" href="https://tailwindcss.com/">Tailwind</a>)</li>
</ul>
<p>Dozens of other tools, like <a target="_blank" href="https://open-props.style/">Open Props</a>, fit somewhere in between.</p>
<h3 id="heading-off-the-shelf-component-libraries">Off-the-Shelf Component Libraries</h3>
<p>If you’re building an interactive web application, you might just want to grab a suite of components that look great and function well. There are many of these off-the-shelf component libraries that give you everything you need and more.</p>
<p>Regardless of which framework you’re writing your app with, there’s likely to be a set of great looking components for you to use.</p>
<p>Another great component library is <a target="_blank" href="https://shoelace.style/">Shoelace</a>, which provides dozens of fully interactive and fully-styled components.</p>
<p>What makes libraries like Shoelace particularly interesting is that it’s built using web components, the browser’s built-in way of writing components. Building your UIs with tools like Shoelace gives you the added benefit of being able to use them across different frontend frameworks. <a target="_blank" href="https://component-odyssey.com/articles/01-writing-components-that-work-in-any-framework">This is something I’ve spoken a little about in the past.</a></p>
<p>Here's the same Shoelace component being used in Vue and React:</p>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/anphi6seqnbqvjd0q7ty.gif" alt="Shoelace buttons in Vue and React" width="1308" height="720" loading="lazy"></p>
<h3 id="heading-un-styled-components">Un-styled Components</h3>
<p>Depending on your project’s specs, you might not have the luxury of using an off-the-shelf tool. Your design specs might be very specific.</p>
<p>I’ve seen teams roll out components at the first sign of friction. And in one case of a hand-rolled data picker, it led to a way worse user experience. In retrospect, using an un-styled component library would have given the team flexibility with appearance, while ensuring that the notoriously tricky time-related behaviour was correct.</p>
<p>That’s why you can reach for a library out there that offers completely un-styled components with flexible styling hooks. If it’s a good library, it’ll also take care of all those complex interactions. It’s a best of both worlds situation.</p>
<p>It’s easy to mess up a checkbox if you want to push beyond the styling hooks that the browser provides, unless you test with a wide-range of devices and input modes.</p>
<div class="embed-wrapper">
        <iframe width="640" height="360" src="https://player.vimeo.com/video/995085532" style="aspect-ratio: 16 / 9; width: 100%; height: auto;" title="Vimeo embed" allow="autoplay; fullscreen; picture-in-picture" allowfullscreen="" loading="lazy"></iframe></div>
<p> </p>
<p><a target="_blank" href="https://www.radix-ui.com/">Radix</a> is a popular example of a library, but it’s built using React.</p>
<p>Other examples of component libraries like this are <a target="_blank" href="https://lion-web.netlify.app/">Lion</a> and <a target="_blank" href="https://headlessui.com/">HeadlessUI</a>.</p>
<h3 id="heading-copy-pastable-component-libraries">Copy-Pastable Component Libraries</h3>
<p>Some developers might want the best of both worlds. They might want a component built by a trusted third-party library, while also having full control over the markup, styles, and functionality.</p>
<p>Libraries like <a target="_blank" href="https://ui.shadcn.com/">ShadCN</a> allow for this kind of work flow by allowing developers to copy and paste the component definition into their own projects, effectively letting them <em>own</em> the component.</p>
<h2 id="heading-why-isnt-there-one-component-library-to-rule-them-all">Why Isn’t There One Component Library to Rule Them All?</h2>
<p>At this point, it’s probably clear why no such single component library exists. We’ve taken a non-exhaustive look at different groups of component libraries.</p>
<p>There is, however, a movement to introduce a “<a target="_blank" href="https://bradfrost.com/blog/post/a-global-design-system/">Global Design System</a>”, a concept spearheaded by Brad Frost.</p>
<p>In the announcement, Brad outlines that in the hundreds of projects he’s been a part of, many of the UI controls behave (or should behave) similarly across these various projects – but developers reimplement the same thing in every single project.</p>
<p>This has lead to lots of wasted time and effort, and inconsistencies between projects. This also expands to the existing component libraries out there. You’ll see that the keyboard behaviour for a combobox in React Aria, is different to that of the combobox in ShadCN.</p>
<div class="embed-wrapper">
        <iframe width="640" height="360" src="https://player.vimeo.com/video/995085659" style="aspect-ratio: 16 / 9; width: 100%; height: auto;" title="Vimeo embed" allow="autoplay; fullscreen; picture-in-picture" allowfullscreen="" loading="lazy"></iframe></div>
<p> </p>
<p>Brad Frost is proposing a Global Design System as a set of web components that should be adoptable by almost any frontend project to ensure a baseline of functionality for the controls that are not yet available in HTML.</p>
<p>There are <a target="_blank" href="https://github.com/openui/open-ui/issues/1066">discussions going on within the Open UI</a> to see how this could start taking shape within the next few years.</p>
<h2 id="heading-should-you-build-your-own-component-library">Should You Build Your Own Component Library?</h2>
<p>This article has delved deeply into component libraries. And with all that context, you’ll inevitably start asking yourself, when you're staring at the empty HTML page for your next big project, whether you should build your own component library or use an existing one.</p>
<p>My first thought is: <em>I don’t think you should build your own library.</em></p>
<p>I generally favour picking a battle-tested library. Particularly one that has:</p>
<ul>
<li><p>Been used across thousands of projects</p>
</li>
<li><p>A strong community, in Discord or GitHub</p>
</li>
<li><p>Great documentation</p>
</li>
<li><p>A strong focus on accessibility</p>
</li>
<li><p>Worked with the strengths of the chosen framework</p>
</li>
</ul>
<p>Most importantly out of all of these is to use a component library that puts care into building accessible components.</p>
<p>Take a combobox, for instance. It’s a search input and a select menu mixed into one. If you’ve built your own, you may get it looking good, and working with your mouse. But you’ll also need to consider:</p>
<ul>
<li><p>Cross browser support</p>
</li>
<li><p>Tab and focus behaviour</p>
</li>
<li><p>Screen reader support</p>
</li>
<li><p>Handling states for async loading of search results</p>
</li>
</ul>
<p>Konnor Rogers, who does excellent work in the web + web component space, has shared countless frustrations with his experiences building an accessible combobox. Here’s one such <a target="_blank" href="https://x.com/RogersKonnor/status/1797529313279140294">tweet he shared</a>.</p>
<p>Screen reader support is particularly complex, and is worth of its own bullet-point list. To support screen readers, you’ll also need to handle:</p>
<ul>
<li><p>live regions</p>
</li>
<li><p>interactive controls</p>
</li>
<li><p>selected items</p>
</li>
<li><p>support between different screen readers</p>
</li>
</ul>
<p>As a side note, I only have access to Voiceover, meaning it’s difficult for me to test these complex UI patterns using different screen readers. Like browsers, there are differences between screen readers. In this article, <a target="_blank" href="https://www.scottohara.me/blog/2022/02/05/are-we-live.html">Are We Live?</a>, Scott O’Hara describes how there’s variance among the difference with how they treat the live regions.</p>
<p>This means it’s also up to you, as the developer, to pick a component library that you can trust has been developed with accessibility in mind. This is why it’s also important to pick a component library that has a strong community.</p>
<p>You should be able to:</p>
<ul>
<li><p>See the bugs and issues others have flagged for a given library</p>
</li>
<li><p>Suggest (or even contribute) improvements and changes to the library</p>
</li>
<li><p>Discuss ideas with members of the community and build working relationships with active members of the community or even maintainers themselves</p>
</li>
</ul>
<p>Finally, and not least, a great component library will consider much more than the aesthetics of its components. For a component library designed for the web, it should try it’s best to:</p>
<ul>
<li><p>adhere to the <a target="_blank" href="https://www.w3.org/TR/WCAG21/">Web Content Accessibility Guidelines (WCAG)</a></p>
</li>
<li><p>ensure that the components work across different input modalities (touch, keyboard, screen reader)</p>
</li>
<li><p>ensure that the components are usable for folks with additional requirements, like those living with vestibular disorders, vision impairments, or a broken hand.</p>
</li>
</ul>
<h2 id="heading-when-and-why-its-useful-to-build-your-own-component-library">When (and Why) It's Useful to Build Your Own Component Library</h2>
<p>If I haven’t scared you off from building a component library, then let me contradict myself and explain why it can be a really good thing to build your own.</p>
<p>If you take the time to put care and attention into building a component library, then you’ll find yourself a becoming developer who better understands the browser platform, accessibility best practices, testing practices, and more.</p>
<p>But it doesn’t just stop there: there are some excellent reasons to build your own library.</p>
<p>For starters, you can build something tailored to your needs, and avoid some of the bloat you might get form an off-the-shelf component library. It’s up to you and your team to understand your end users, and you can build something specifically for them.</p>
<p>You also have the opportunity to experiment with novel approaches. If you have a hyper-niche problem, there might not be a component library out there to solves that need. It could be a component library that:</p>
<ul>
<li><p>Visualises data in specific way</p>
</li>
<li><p>Has a distinct and unique visual identity</p>
</li>
<li><p>Is built on a new framework</p>
</li>
</ul>
<p>That gives you the opportunity to build something tailored to your needs. You then have the opportunity to change and fix things as your needs change, or as you understand the problem space better.</p>
<p>Importantly, you’ll learn more about the web by doing so. If it’s your first time building a component library, it can be an opportunity to dive deeper into the <a target="_blank" href="https://html.spec.whatwg.org/multipage/">HTML browser specs</a>, or brush up on your <a target="_blank" href="https://www.w3.org/TR/WCAG21/">web accessibility knowledge</a>. This will improve your abilities as a web developer, which will serve you well in any frontend project in the future. It could even help you land your next job.</p>
<p>So whether you should build a component library depends on your end goals. Consider questions like:</p>
<ul>
<li><p>Do I want to better understand the browser?</p>
</li>
<li><p>Do I want to build something quickly?</p>
</li>
<li><p>Do I want to make it usable for as many users as possible?</p>
</li>
<li><p>Do libraries exist that solve my current problem?</p>
</li>
</ul>
<p>Depending on what your answers are, you can make the right call for your project.</p>
<h2 id="heading-thanks-for-reading">Thanks for Reading!</h2>
<p>Thanks for learning about component libraries with me. If you're interested in building your own web component library, then consider checking out my course <a target="_blank" href="https://component-odyssey.com/">Component Odyssey</a>. You'll learn how to build and publish a component library that works in any frontend framework.</p>
<p>💡 I want to give a special shoutout to stephband (<a target="_blank" href="https://front-end.social/@stephband">Mastodon</a>, <a target="_blank" href="https://bsky.app/profile/stephen.band">Bluesky</a>) for proofreading and providing feedback.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Use New CSS Features to Build a Progress Indicator ]]>
                </title>
                <description>
                    <![CDATA[ For the last 7 months, I’ve had my head down building Component Odyssey. It’s been a richly fulfilling project and I’m eager for people to take the course and learn heaps about building component libraries using web components. I’ve seen some incredi... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/use-new-css-features-to-build-a-progress-indicator/</link>
                <guid isPermaLink="false">66bb8e04b0d3ac3d7acde3ee</guid>
                
                    <category>
                        <![CDATA[ CSS ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Web Design ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Web Development ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Andrico Karoulla ]]>
                </dc:creator>
                <pubDate>Tue, 09 Jan 2024 15:39:50 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2024/01/open-graph.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>For the last 7 months, I’ve had my head down building <a target="_blank" href="https://component-odyssey.com/">Component Odyssey</a>. It’s been a richly fulfilling project and I’m eager for people to take the course and learn heaps about building component libraries using web components.</p>
<p>I’ve seen some incredible demos over the past year, and wanted to sink my teeth into some of these cool new features. So I used some downtime over the Christmas period to cram tons of new CSS features into a lesson progress indicator for the Component Odyssey platform. </p>
<p>The result is the following progress indicator that shows how much of the page the user has scrolled:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/01/component-odyssey-indicator.gif" alt="the fully completed progress indicator as it exists on Component Odyssey" width="600" height="400" loading="lazy"></p>
<p>Building it gave me some exposure to some of the latest CSS features like:</p>
<ul>
<li><code>animation-timeline: scroll()</code></li>
<li>CSS trig functions, <code>sin()</code> and <code>cos()</code></li>
<li><code>color-mix()</code></li>
<li>the <code>@property</code> at-rule</li>
</ul>
<p>I know the risks of building something with a particular tool in mind. As the saying goes “When all you have is a hammer, then <em>something something</em> nails”.</p>
<p>Yes, I have a hammer, and I’m going to smash the walls down with it.</p>
<p>In this article, I’ll run through how to create a pared-down version of this swanky progress animation while still using all of the CSS features mentioned above. I’ll also show you how to gracefully handle browsers that don’t support these features through <strong>progressive enhancement</strong>.</p>
<p>If you want to follow along, then it’s best to use the latest versions of Chrome or Safari – currently Firefox doesn’t have general support for properties like <code>animation-timeline</code>. Get started by jumping into the <a target="_blank" href="https://codepen.io/andrico1234/pen/WNmQrGK">starter Codepen</a>.</p>
<p>If you want to peruse the finished code, you can <a target="_blank" href="https://codepen.io/andrico1234/pen/qBvdjLd">check it out here.</a></p>
<h2 id="heading-how-to-create-the-markup">How to Create the Markup</h2>
<p>I’ve already provided a little markup to simulate a page with enough content that you'll need to scroll to get to the bottom. To get started creating the progress indicator, you’ll need to add some more markup.</p>
<p>The markup itself is really simple – we’ll only need to create 3 div elements.</p>
<p>The outer element is responsible for the positioning and layout of the loader. We’ll give this a class of <code>wrapper</code>.</p>
<p>The middle element is responsible for rendering the track to the screen. We’ll give this element a class of <code>progress</code>. We’ll later use an <code>::after</code> pseudo-element to create the <em>indicator thumb</em>.</p>
<p>The innermost element will be used to create the circular hole in the middle, making the indicator look like a low-calorie doughnut. This will have a class of <code>inner</code>.</p>
<p>Take a look at the following if you need a hand visualising the structure:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/01/markup-structure.png" alt="A visual representation of the information outlined above" width="600" height="400" loading="lazy">
<em>Illustration of the markup structure</em></p>
<p>Provide the following markup as the first child of the <code>main</code> element creates the following markup:</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"wrapper"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"progress"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"inner"</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>
<h3 id="heading-applying-the-base-css-to-the-markup">Applying the Base CSS to the Markup</h3>
<p>You’ll also need to apply the following styles to give the markup a base visual appearance:</p>
<pre><code class="lang-css"><span class="hljs-selector-class">.wrapper</span> {
    <span class="hljs-attribute">--size</span>: <span class="hljs-number">80px</span>;

    <span class="hljs-attribute">position</span>: fixed;
    <span class="hljs-attribute">width</span>: <span class="hljs-built_in">var</span>(--size);
    <span class="hljs-attribute">aspect-ratio</span>: <span class="hljs-number">1</span>/<span class="hljs-number">1</span>;
    <span class="hljs-attribute">top</span>: <span class="hljs-number">24px</span>;
    <span class="hljs-attribute">left</span>: <span class="hljs-number">24px</span>;
    <span class="hljs-attribute">display</span>: flex;
    <span class="hljs-attribute">align-items</span>: center;
    <span class="hljs-attribute">justify-content</span>: center;
}

<span class="hljs-selector-class">.progress</span> {
    <span class="hljs-attribute">--track-size</span>: <span class="hljs-number">16px</span>;

    <span class="hljs-attribute">width</span>: <span class="hljs-built_in">var</span>(--size);
    <span class="hljs-attribute">aspect-ratio</span>: <span class="hljs-number">1</span>/<span class="hljs-number">1</span>;
    <span class="hljs-attribute">border-radius</span>: <span class="hljs-number">50%</span>;
}

<span class="hljs-selector-class">.inner</span> {
    <span class="hljs-attribute">position</span>: absolute;
    <span class="hljs-attribute">width</span>: <span class="hljs-built_in">calc</span>(<span class="hljs-number">100%</span> - var(--track-size));
    <span class="hljs-attribute">aspect-ratio</span>: <span class="hljs-number">1</span>/<span class="hljs-number">1</span>;
    <span class="hljs-attribute">background</span>: <span class="hljs-built_in">var</span>(--background-color);
    <span class="hljs-attribute">border-radius</span>: <span class="hljs-number">50%</span>;
    <span class="hljs-attribute">top</span>: <span class="hljs-number">0</span>;
    <span class="hljs-attribute">left</span>: <span class="hljs-number">0</span>;
    <span class="hljs-attribute">right</span>: <span class="hljs-number">0</span>;
    <span class="hljs-attribute">bottom</span>: <span class="hljs-number">0</span>;
    <span class="hljs-attribute">margin</span>: auto;
}
</code></pre>
<p>Most of the CSS here shouldn’t come as a shock to you, so I won’t go over it line by line. But I will touch on some of the more interesting bits.</p>
<p>In <code>.wrapper</code>, we’re fixing the element to the top left of the screen, and we're using Flexbox to center the children horizontally and vertically.</p>
<p>💡 I learned that if you want an element to share the same value for both its width and height, you just set the width and use <code>aspect-ratio: 1/1</code>. The browser will implicitly set the height. </p>
<p>This is a neat trick because you won’t have to define the same value twice, and it makes it easier to guarantee that the width and the height share the same value.</p>
<p>As for the <code>.inner</code> element, I’ve used a mix of absolute positioning and the <code>margin: auto</code> to center it in the middle of the <code>.progress</code> element. We’ve also deducted the <code>--track-size</code> from the full width of the container, to ensure that it’s correctly positioned over the <code>.progress</code> element.</p>
<p>You won’t be able to see anything just yet, but if you add a temporary <code>background-color: red</code> to the <code>.progress</code> element, it should render as follows:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/01/basic-ui.png" alt="a basic doughnut shaped indacator without any animation" width="600" height="400" loading="lazy">
<em>Image showing the current state of the progress indicator - a red circle</em></p>
<h2 id="heading-how-to-create-an-animated-progress-indicator">How to Create an Animated Progress Indicator</h2>
<p>Creating a scroll-driven animation of this kind requires a lot of new CSS features that you may have not used before. Instead of learning everything all at once, we’ll start by decoupling the animation from the scrolling mechanics.</p>
<p>That way, by the end of this section, you should have the following animation that plays automatically:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/01/infinite-loading.gif" alt="A progress indicator playing automatically in an infinite loop" width="600" height="400" loading="lazy">
<em>Animation showing the initial stage of the progress indicator</em></p>
<p>We’ll start by creating a new animation called <code>load</code>:</p>
<pre><code class="lang-css"><span class="hljs-keyword">@keyframes</span> load {
    0% {
        <span class="hljs-attribute">--progress</span>: <span class="hljs-number">0%</span>;
    }

    100% {
        <span class="hljs-attribute">--progress</span>: <span class="hljs-number">100%</span>;
    }
}
</code></pre>
<p>All this does is move the progress along from 0 to 100 over the course of the animation. </p>
<h3 id="heading-using-conic-gradient-to-indicate-the-current-progress">Using <code>conic-gradient</code> to Indicate the Current Progress</h3>
<p>In your <code>.progress</code> rule, add the following CSS properties:</p>
<pre><code class="lang-css"><span class="hljs-selector-class">.progress</span> {
    # Existing rules

    <span class="hljs-attribute">animation</span>: load linear <span class="hljs-number">1s</span> infinite;
    <span class="hljs-attribute">background</span>: <span class="hljs-built_in">conic-gradient</span>(
        from <span class="hljs-number">0deg</span> at <span class="hljs-number">50%</span> <span class="hljs-number">50%</span>,
        var(--red) <span class="hljs-built_in">var</span>(--progress),
        <span class="hljs-built_in">var</span>(--black) <span class="hljs-built_in">var</span>(--progress)
    )
}
</code></pre>
<p>The <code>animation</code> property should be pretty straightforward, but there’s a lot going on with the <code>background</code> rule, so let’s step through it.</p>
<p>For starters, we’re using a <code>conic-gradient</code> as it makes it easy for us to animate the background over 360 degrees, in the way shown in the animation above. We’re starting from the <code>0deg</code> position, which is top and center. We’re describing where we want the center of the gradient to be using <code>at 50% 50%</code>.</p>
<p><code>conic-gradient(from 0deg at 50% 50%)</code> alone would render something like the following:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/01/radial-gradient.png" alt="A visualisation of a radial gradient starting from the center, like a sonar radar" width="600" height="400" loading="lazy">
<em>Image showing a red circle witha slight gradient, the result of <code>conic-gradient(from 0deg at 50% 50%)</code> alone</em></p>
<p>Hopefully I’ve made it clear why that’s the case.</p>
<p>As for the the second and third arguments of the <code>conic-gradient</code> function, we’re linking the <code>--progress</code> variable (which is being calculated via the <code>load</code> animation) to the two colors. The <code>--red</code> is used to denote the completed progress, while the <code>--black</code> is used to denote the remaining position. </p>
<p>It might be confusing why they share the same <code>--progress</code> value. The <code>--progress</code> value for the <code>--red</code> value denotes where the gradient stop ends, while the <code>--progress</code> value for the <code>--black</code> denotes where the gradient stop begins. </p>
<p>Because it’s the last stop on the gradient, it’s implied that it ends at 100%. By setting the same <code>--progress</code> value to both stops in the gradient, we create a hard transition between the two colors. Without doing so, our progress indicator (with a <code>--progress</code> value set to 16%) would look like this:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/01/radial-gradient-no-stop.png" alt="The progress indicator where the color gradient goes slowly from red to black" width="600" height="400" loading="lazy">
<em>Progress indicator with a red to black gradient and no animation</em></p>
<h3 id="heading-animating-the-gradient">Animating the Gradient</h3>
<p>Now, something strange is probably happening. Instead of your progress indicator transitioning gracefully across the entire perimeter of the circle, it’s instead flashing between the black and red.</p>
<p>Why is this happening?</p>
<p>This is because we’re making the browser interpolate between percentage values, which is something it can’t do automatically. Even though we’ve given the <code>--progress</code> variable a percentage value, the browser doesn’t assume that it’s always going to be a percentage value.</p>
<p>We can solve this by telling the browser that <code>--progress</code> will always be a percentage value. We can do this by explicitly defining the <code>--progress</code> property using the <code>@property</code> CSS rule. Just add the following to the top-level of your CSS:</p>
<pre><code class="lang-css"><span class="hljs-keyword">@property</span> --progress {
    <span class="hljs-selector-tag">syntax</span>: '&lt;<span class="hljs-selector-tag">percentage</span>&gt;';
    <span class="hljs-selector-tag">inherits</span>: <span class="hljs-selector-tag">false</span>;
    <span class="hljs-selector-tag">initial-value</span>: 0%;
}
</code></pre>
<p>We’re telling the browser that <code>--progress</code> should only support percentage values and that the initial value is 0%. We’re also not interested in having the custom element inherit its value.</p>
<p>Finally, I don’t quite like the use of the <code>--black</code> variable to signify empty progress. It looks too stark. I’d like to create a lighter shade created from the black to ensure a more homogenous visual palette. This is something we can easily achieve using the <code>color-mix()</code> CSS function.</p>
<p>Jump back up to the <code>:root</code> CSS rule and add the following variable:</p>
<pre><code class="lang-css"><span class="hljs-selector-pseudo">:root</span> {
    # your other CSS variables

    <span class="hljs-attribute">--grey</span>: <span class="hljs-built_in">color-mix</span>(in srgb, var(--black), transparent <span class="hljs-number">60%</span>);
}
</code></pre>
<p>The <code>color-mix</code> function lets us mix two colors together. In this case, we’re mixing the color stored in our black variable with some transparency, which will result in a partially see-through grey color. You’ll need to replace the reference to the <code>--black</code> variable in the <code>conic-gradient</code> function with <code>--grey</code> to see the color change in effect.</p>
<p>Now that we’ve defined our custom property, the browser will be able to interpolate the correct values during the entire animation, so it should now transition smoothly from start to finish.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/01/infinite-loading-1.gif" alt="A progress indicator playing automatically in an infinite loop" width="600" height="400" loading="lazy">
<em>Showing the animation functioning properly</em></p>
<h2 id="heading-how-to-enable-scroll-driven-animations">How to Enable Scroll-driven Animations</h2>
<p>The next stage of our animation journey is to tie our animation to the scrolling of the page.</p>
<p>This should only take us a couple of lines of CSS.</p>
<p>You’ll need to do two things: first adjust the <code>animation</code> property in your <code>.progress</code> class to remove the <code>infinite</code> value, and to change the duration from <code>1s</code> to <code>1ms</code>. We can’t remove the value altogether because Firefox needs it for scroll animations to work.</p>
<p>Next update your <code>.progress</code> class to include the following:</p>
<pre><code class="lang-css"><span class="hljs-selector-class">.progress</span> {
  # other CSS properties

    <span class="hljs-attribute">animation-timeline</span>: <span class="hljs-built_in">scroll</span>(nearest block);
}
</code></pre>
<p>The <code>animation-timeline</code> property tells the browser to tie the progress of the animation with a specific timeline. In this case it’s the scroll timeline, which we specify using the <code>scroll</code> function.</p>
<p>You can see I’m providing two arguments to <code>scroll()</code>: <code>nearest</code> and <code>block</code>.</p>
<p>The <code>nearest</code> value is used to tie the animation to the nearest ancestor that has a scrollbar. In this case it’s the document. If you’re certain that you only ever want to tie the animation to the document’s scrollbar, then you can swap out <code>nearest</code> for <code>root</code> instead.</p>
<p>The <code>block</code> property denotes the axis that we want to tie our animation to. For most cases this will be the vertical scrollbar, but for vertical writing modes, this will be the horizontal scrollbar.</p>
<p>Now that you’ve hooked up the animation to your page’s scroll, you should be able to scroll up and down the page and watch how your animation changes accordingly.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/01/progress-complete.gif" alt="The basic progress indicator whose animation is tied to the progress of the page scroll" width="600" height="400" loading="lazy">
<em>Demo showing a user scorlling and the animation of the scroll element changing</em></p>
<h2 id="heading-how-to-progressively-enhance-your-scroll-animation">How to Progressively Enhance Your Scroll Animation</h2>
<p>While it’s exciting to use these new features in the browser, the <code>animation-timeline</code> property doesn’t have universal support across browsers yet. It’s still very new in Chrome, and it’s only available in Firefox behind a feature flag. If you try opening the code in Firefox, you’ll notice that the progress ring just appears with a finished animation.</p>
<p>In cases like this, it’s important to set up a solid base experience for all browsers, and then <em>progressively enhance</em> your webpage with the newer features on compatible browsers. Because the progress indicator isn’t critical for the application to function, we can just hide it away if the browser doesn’t support the <code>animation-timeline</code> property.</p>
<p>We can do this by moving our <code>.wrapper</code>, <code>.progress</code>, and <code>.inner</code> classes within CSS’s <code>@supports</code> at-rule, like so:</p>
<pre><code class="lang-css"><span class="hljs-keyword">@supports</span> (<span class="hljs-attribute">animation-timeline:</span> scroll()) {
    <span class="hljs-selector-class">.wrapper</span> {}

    <span class="hljs-selector-class">.progress</span> {}

    <span class="hljs-selector-class">.inner</span> {}
}
</code></pre>
<p>Doing so ensures that if the browser doesn’t support <code>scroll()</code>, then it will ignore all of the styles contained within the rule.</p>
<h2 id="heading-how-to-add-the-indicator-thumb">How to Add the Indicator Thumb</h2>
<p>The final thing for us to add is a cool little indicator thumb, to both give our progress indicator a little more visual interest and to also let us play with the swanky CSS trigonometric functions.</p>
<p>The <em>indicator thumb</em> is the little circular element that indicates the exact current progress </p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/01/thumb-indicator.png" alt="The indicator thumb placed at 4 o'clock on the progress indicator" width="600" height="400" loading="lazy">
<em>Illustration showing the indicator thumb (a dark dot on the progress indicator)</em></p>
<h3 id="heading-creating-the-thumbs-visual-appearance">Creating the Thumb's Visual Appearance</h3>
<p>To create the indicator thumb, start by writing the following CSS inside of the <code>@supports</code> block:</p>
<pre><code class="lang-css"><span class="hljs-selector-class">.progress</span><span class="hljs-selector-pseudo">::after</span> {
    <span class="hljs-attribute">--radius</span>: <span class="hljs-built_in">calc</span>(var(--size) / <span class="hljs-number">2</span>);
    <span class="hljs-attribute">--track-offset</span>: <span class="hljs-built_in">calc</span>(var(--track-size) / <span class="hljs-number">4</span>);

    <span class="hljs-attribute">content</span>: <span class="hljs-string">''</span>;
    <span class="hljs-attribute">position</span>: absolute;
    <span class="hljs-attribute">aspect-ratio</span>: <span class="hljs-number">1</span>/<span class="hljs-number">1</span>;
    <span class="hljs-attribute">width</span>: <span class="hljs-built_in">calc</span>(var(--track-size) / <span class="hljs-number">2</span>);
    <span class="hljs-attribute">background</span>: <span class="hljs-built_in">var</span>(--red-dark);
    <span class="hljs-attribute">border-radius</span>: <span class="hljs-number">50%</span>;
    <span class="hljs-attribute">left</span>: <span class="hljs-built_in">calc</span>(<span class="hljs-number">50%</span> - var(--track-offset));
    <span class="hljs-attribute">top</span>: <span class="hljs-built_in">calc</span>(<span class="hljs-number">50%</span> - var(--track-offset));
    <span class="hljs-attribute">transform</span>: <span class="hljs-built_in">scale</span>(<span class="hljs-number">1.5</span>);
}
</code></pre>
<p>This creates a new pseudo-element off of the <code>.progress</code> class, and gives it its visual appearance. Once added, the indicator thumb should live in the center progress element. We’re using the <code>--track-offset</code> variable to position the thumb correctly by taking into consideration the dimensions of the track.</p>
<p>⚠️ I’m also increasing the size of the thumb to using <code>scale()</code> so that its size in the DOM is still relative to the <code>--size</code> variable. This just means a little less math for us to worry about when setting the value for <code>--track-offset</code>. Using <code>scale()</code> makes it easy to change the size of the element without causing a shift in the DOM.</p>
<p>The next step is to use the <code>color-mix()</code> function again to create a dark red from the base red color. Add the following to your <code>:root</code> rule.</p>
<pre><code class="lang-css"><span class="hljs-selector-pseudo">:root</span> {
    # your other CSS variables

    <span class="hljs-attribute">--red-dark</span>: <span class="hljs-built_in">color-mix</span>(in srgb, var(--red), <span class="hljs-built_in">var</span>(--black) <span class="hljs-number">60%</span>);
}
</code></pre>
<p>Your progress indicator should look less like a UI widget and more like a dartboard:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/01/bullseye.png" alt="the thumb is in the center of the progress indicator" width="600" height="400" loading="lazy">
<em>Animation/indicator thumb in progress</em></p>
<h3 id="heading-positioning-the-thumb-on-the-track">Positioning the Thumb on the Track</h3>
<p>Let’s position the thumb on to the track.</p>
<pre><code class="lang-css"><span class="hljs-selector-class">.progress</span><span class="hljs-selector-pseudo">::before</span> {
  # rest of properties

    <span class="hljs-attribute">translate</span>: <span class="hljs-built_in">calc</span>((var(--radius) - <span class="hljs-built_in">var</span>(--track-offset)) * <span class="hljs-built_in">cos</span>(var(--angle)))
      <span class="hljs-built_in">calc</span>((var(--radius) - <span class="hljs-built_in">var</span>(--track-offset)) * <span class="hljs-built_in">sin</span>(var(--angle)));
}
</code></pre>
<p>This is probably the gnarliest piece of CSS in this entire article. It isn’t anywhere near as complex if we break it down in half. Here’s the first half:</p>
<pre><code class="lang-css"><span class="hljs-selector-tag">calc</span>((<span class="hljs-selector-tag">var</span>(<span class="hljs-selector-tag">--radius</span>) <span class="hljs-selector-tag">-</span> <span class="hljs-selector-tag">var</span>(<span class="hljs-selector-tag">--track-offset</span>)) * <span class="hljs-selector-tag">cos</span>(<span class="hljs-selector-tag">var</span>(<span class="hljs-selector-tag">--angle</span>)))
</code></pre>
<p>This uses a little trigonometry to calculate the position of the thumb based on the current angle (which will be tied to the scroll progress) and the radius of the circle. The <code>cos()</code> function is used to determine the horizontal value of the position.</p>
<p>The second half of the value is identical, except we’re using the <code>sin()</code> function to determine the vertical position of the indicator:</p>
<pre><code class="lang-css"><span class="hljs-selector-tag">calc</span>((<span class="hljs-selector-tag">var</span>(<span class="hljs-selector-tag">--radius</span>) <span class="hljs-selector-tag">-</span> <span class="hljs-selector-tag">var</span>(<span class="hljs-selector-tag">--track-offset</span>)) * <span class="hljs-selector-tag">sin</span>(<span class="hljs-selector-tag">var</span>(<span class="hljs-selector-tag">--angle</span>)))
</code></pre>
<p><em>⚠️</em> I’m not going to use this article as an introduction into trigonometry, but I can point you in the direction of some amazing resources:</p>
<ul>
<li><a target="_blank" href="https://web.dev/articles/css-trig-functions">Trigonometric functions in CSS</a></li>
<li><a target="_blank" href="https://tympanus.net/codrops/2021/06/04/trigonometry-in-css-and-javascript-beyond-triangles/">Trigonometric functions in CSS and JavaScript: Beyond Triangles</a></li>
</ul>
<p>You may have noticed that I’ve specified a variable, <code>--angle</code>, that I haven’t yet defined. Because we’ll be animating the <code>--angle</code>, we need to explicitly define it using the <code>@property</code> rule, much like we did for the <code>--progress</code> property. The only difference is that we’ll need to specify a different syntax value. Instead of <code>&lt;percentage&gt;</code> the value will need to be <code>&lt;angle&gt;</code>:</p>
<pre><code class="lang-css"><span class="hljs-keyword">@property</span> --angle {
    <span class="hljs-selector-tag">syntax</span>: '&lt;<span class="hljs-selector-tag">angle</span>&gt;';
    <span class="hljs-selector-tag">inherits</span>: <span class="hljs-selector-tag">false</span>;
    <span class="hljs-selector-tag">initial-value</span>: <span class="hljs-selector-tag">-90deg</span>;
}
</code></pre>
<p>By setting the initial value to <code>-90deg</code>, we ensure that the thumb is placed at the 12 o’clock position on the progress indicator.</p>
<p>Your indicator should now look like this:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/01/positioned-thumb.png" alt="The thumb is positioned at the top center of the progress indicator" width="600" height="400" loading="lazy">
<em>Showing the thumb now on the track of the progress indicator</em></p>
<p>The next step is to create the animation for the thumb and then bind the animation timeline to the scroll position of the page.</p>
<h3 id="heading-animating-the-thumb-indicator">Animating the Thumb Indicator</h3>
<p>Let’s start by creating a new animation:</p>
<pre><code class="lang-css"><span class="hljs-keyword">@keyframes</span> rotate {
    0% {
        <span class="hljs-attribute">--angle</span>: -<span class="hljs-number">90deg</span>;
    }

    100% {
        <span class="hljs-attribute">--angle</span>: <span class="hljs-number">270deg</span>;
    }
}
</code></pre>
<p>Over the course of the entire animation, the thumb will rotate 360 degrees, performing a full revolution over the progress element.</p>
<p>Finally we need to add the following two properties to the thumb:</p>
<pre><code class="lang-css"><span class="hljs-selector-class">.progress</span><span class="hljs-selector-pseudo">::after</span> {
    # other CSS properties

    <span class="hljs-attribute">animation</span>: rotate linear <span class="hljs-number">1ms</span>;
    <span class="hljs-attribute">animation-timeline</span>: <span class="hljs-built_in">scroll</span>(nearest block);
}
</code></pre>
<p>Doing so applies the rotate animation to our thumb and binds it to the scroll position.</p>
<p>Everything should now work flawlessly:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/01/thumb-complete.gif" alt="The completed progress indicator UI" width="600" height="400" loading="lazy">
<em>Final product showing the animation working smoothly as a user scrolls</em></p>
<h2 id="heading-wrapping-up">Wrapping up</h2>
<p>I created this progress indicator specifically to become more familiar with the amazing tools that CSS has shipped in the last couple years. Hopefully you learnt just as much from this lesson as I did making it.</p>
<p>There were other CSS features I wanted to explore, like <code>popover</code> and <code>:has</code> but I couldn’t find a way to fit them in with this animation. If you find this article interesting, I might try and create more little changes to the Component Odyssey platform, using cutting-edge CSS features.</p>
<p>By wary, because a lot of the CSS features I’ve covered are still very new. So you should check the browser support before using them in production. </p>
<p>If they’re not supported in one or more browsers, but you’re desperate to use them, then use a <strong>progressive enhancement</strong> strategy (as I went over in this tutorial) to ensure that those with compatible browsers get the full experience, while still offering users of unsupported browsers a solid baseline experience.</p>
<p>If you enjoyed this article, and would love to learn more about Component Odyssey or other cool web development tips, then consider <a target="_blank" href="https://component-odyssey.com/subscribe">subscribing to the newsletter</a>.</p>
<h3 id="heading-resources">Resources</h3>
<ul>
<li><a target="_blank" href="https://developer.chrome.com/docs/css-ui/scroll-driven-animations#getting_practical_with_scroll_progress_timelines">Getting practical with scroll progress timelines</a></li>
<li><a target="_blank" href="https://dev.to/afif/we-can-finally-animate-css-gradient-kdk">We can finally animate CSS gradients</a></li>
<li><a target="_blank" href="https://codepen.io/LukyVj/pen/rNqvowZ">Fitness inspired loaders</a></li>
<li><a target="_blank" href="https://drafts.css-houdini.org/css-properties-values-api-1/#at-property-rule">MDN: @property at-rule</a></li>
<li><a target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/CSS/animation-timeline">MDN: Animation Timeline</a></li>
</ul>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Write Components that Work in Any Framework ]]>
                </title>
                <description>
                    <![CDATA[ The browser has a built-in way of writing reusable components in the form of web components. They’re an excellent choice for building interactive and reusable components that work in any frontend framework.  With that said, writing highly interactive... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/write-components-that-work-in-any-framework/</link>
                <guid isPermaLink="false">66bb8e07bec1b237336e9685</guid>
                
                    <category>
                        <![CDATA[ components ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Web Development ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Andrico Karoulla ]]>
                </dc:creator>
                <pubDate>Mon, 06 Nov 2023 20:25:12 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2023/11/og-button.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>The browser has a built-in way of writing reusable components in the form of <strong>web components</strong>. They’re an excellent choice for building interactive and reusable components that work in any frontend framework. </p>
<p>With that said, writing highly interactive and robust web components isn’t simple. They require a lot of boilerplate and feel much less intuitive than the components you may have written in frameworks like React, Svelte, or Vue.</p>
<p>In this tutorial, I’ll give you an example of an interactive component written as a web component, and then refactor it using a library that softens the edges and removes heaps of boilerplate.</p>
<p>Don’t sweat it if you’re not familiar with web components. In the next section, I’ll do a (brief) overview of what web components are, and what they’re made out of. If you have some basic experience with them, you can skip the next section.</p>
<h2 id="heading-what-are-web-components">What are Web Components?</h2>
<p>Before web components, the browser didn’t have a standard way of writing reusable components. Many libraries solve this problem, but they often run into limitations like performance, interoperability, and issues with web standards.</p>
<p>Web components are a technology made up of 3 different browser features:</p>
<ul>
<li>Custom elements</li>
<li>Shadow DOM</li>
<li>HTML Templates</li>
</ul>
<p>We’ll do a quick crash course covering these technologies, but it’s by no means a comprehensive breakdown.</p>
<h3 id="heading-what-are-custom-elements">What are Custom Elements?</h3>
<p>With Custom Elements you can author your own custom HTML elements that you can reuse across your site. They can be as simple as text, images, or visual decorations. You can push them further and build interactive components, complex widgets, or entire web applications.</p>
<p>You’re not just limited to using them in your projects, but you can publish them and allow other developers to use them on their sites.</p>
<p>Here are some of the reusable components from my library <a target="_blank" href="https://a2000-docs.netlify.app/">A2K</a>. You can see that they come in all shapes and sizes, and have a range of different functionalities. Using them in your projects is similar to using any old HTML element.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/11/web-components.png" alt="A small collection of web components from the A2K library" width="600" height="400" loading="lazy">
<em>A small collection of web components from the A2K library</em></p>
<p>Here’s how you’d use the progress element in your project:</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>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">head</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">title</span>&gt;</span>Quick Start<span class="hljs-tag">&lt;/<span class="hljs-name">title</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">head</span>&gt;</span>

    <span class="hljs-tag">&lt;<span class="hljs-name">body</span>&gt;</span>
        <span class="hljs-comment">&lt;!-- Use web components in your HTML like regular built-in elements. --&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">a2k-progress</span> <span class="hljs-attr">progress</span>=<span class="hljs-string">"50"</span> /&gt;</span>

        <span class="hljs-comment">&lt;!-- a2k web components use standard JavaScript modules. --&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>&gt;</span><span class="javascript">
            <span class="hljs-keyword">import</span> <span class="hljs-string">'https://cdn.jsdelivr.net/npm/@a2000/progress@0.0.5/lib/src/a2k-progress.js'</span>;
        </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>Once you’ve imported the third-party scripts, you can start using the component, <code>a2k-progress</code> in this case, just like any other HTML element.</p>
<p>If you’re building your own web components, there’s virtually no limit to how complex you can make your custom elements. </p>
<p>I recently created a web component that renders a CodeSandbox code editor in the browser. And because it’s a web component, you can use it in any framework you like! If you’d like to learn a little more about that, <a target="_blank" href="https://component-odyssey.com/articles/00-sandpack-lit-universal">you can read more here</a>.</p>
<h3 id="heading-what-is-the-shadow-dom">What is the Shadow DOM?</h3>
<p>If you have a working knowledge of CSS, you’ll know that vanilla CSS is scoped globally. Writing something like this in your global.css:</p>
<pre><code class="lang-css"><span class="hljs-selector-tag">p</span> {
  <span class="hljs-attribute">color</span>: tomato;
}
</code></pre>
<p>will give all <code>p</code> elements a nice orange/red color, assuming that no other, more specific CSS selectors are applied to a <code>p</code> element.</p>
<p>Take this select menu, for example:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/11/a2k-select-menu.png" alt="A select menu component with a visual design reminiscent of the old Windows operating systems" width="600" height="400" loading="lazy"></p>
<p>It has a distinct character which is driven by the visual design. You might want to use this component, but if your global styles affect things like the font family, the color, or the font size, it could cause issues with the appearance of the component:</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">head</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">style</span>&gt;</span><span class="css">
        <span class="hljs-selector-tag">body</span> {
            <span class="hljs-attribute">color</span>: blue;
            <span class="hljs-attribute">font-size</span>: <span class="hljs-number">12px</span>;
            <span class="hljs-attribute">font-family</span>: system-ui;
        }
    </span><span class="hljs-tag">&lt;/<span class="hljs-name">style</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">head</span>&gt;</span>

<span class="hljs-tag">&lt;<span class="hljs-name">body</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">a2k-select</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">a2k-select</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">body</span>&gt;</span>
</code></pre>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/11/a2k-select-menu-2.png" alt="The same select menu, but with a lot of its defining characteristics overridden by global CSS." width="600" height="400" loading="lazy"></p>
<p>This is where the Shadow DOM comes in. The Shadow DOM is an encapsulation mechanism that prevents the rest of the DOM from interfering with your web components. It ensures that the global styles of the web application don’t interfere with any components that you consume. It also means that component library developers can author their components with the confidence that they’ll look and behave as expected across different web applications.</p>
<p>There’s a lot more nuance when it comes to the Shadow DOM, as well as other features that we’re not going to touch on in this article. If you’d like to learn more about web components though, I have an entire course (<a target="_blank" href="https://component-odyssey.com/">Component Odyssey</a>) dedicated to teaching you how to build reusable components that work in any framework.</p>
<h3 id="heading-html-templates">HTML Templates</h3>
<p>The last feature in our whistle-stop tour of web component features is HTML Templates.</p>
<p>What makes this HTML element different from other elements, is that the browser doesn’t render its content to the page. If you were to write the following HTML you wouldn’t see the text “I’m a header” displayed on the page:</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">body</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">template</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">h1</span>&gt;</span>I'm a header<span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">template</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">body</span>&gt;</span>
</code></pre>
<p>Instead of being used to render the content directly, the content of the template is designed to be copied. The copied template can then be used to render content to the page. </p>
<p>You can think of the template element much like the template for a 3D print. The template isn’t a physical entity, but it’s used to create real-life clones.</p>
<p>You would then reference the template element in your web component, clone it, and render the clone as the markup for your component.</p>
<p>I won’t spend any more time on these web component features, but you’ve probably already noticed that to write vanilla web components, there are a lot of new browser features that you need to know and understand. </p>
<p>You’ll see in the next section that the mental model for building web components doesn’t feel as streamlined as it does for other component frameworks.</p>
<h2 id="heading-how-to-build-a-basic-web-component">How to Build a Basic Web Component</h2>
<p>Now that we’ve briefly covered the fundamental technologies powering a web component, here’s how to build a <em>hello world</em> component:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> template = <span class="hljs-built_in">document</span>.createElement(<span class="hljs-string">'template'</span>);
template.innerHTML = <span class="hljs-string">`&lt;p&gt;Hello World&lt;/p&gt;`</span>;

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">HelloWorld</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">HTMLElement</span> </span>{
    <span class="hljs-keyword">constructor</span>() {
        <span class="hljs-built_in">super</span>();
        <span class="hljs-built_in">this</span>.attachShadow({ <span class="hljs-attr">mode</span>: <span class="hljs-string">'open'</span> });
        <span class="hljs-built_in">this</span>.shadowRoot.append(template.content.cloneNode(<span class="hljs-literal">true</span>));
    }
}

customElements.define(<span class="hljs-string">'hello-world'</span>, HelloWorld);
</code></pre>
<p>This is the most simple component you can write, but there’s already so much going on. For someone completely new to web components, and without the background knowledge I provided above, they’re going to be left with a lot of questions, and a lot of confusion.</p>
<p>For me, there are at least two key reasons why web components can be challenging to write, at least within the context of the hello world examples.</p>
<h3 id="heading-the-markup-is-decoupled-from-the-component-logic">The markup is decoupled from the component logic</h3>
<p>In many frameworks, the markup of the component is often treated as a first-class citizen. It’s often the content that gets returned from the component function, or has direct access to the component’s state, or has built-in utilities to help manipulate markup (like loops, conditionals, and so on).</p>
<p>This isn’t the case for web components. In fact, the markup is often defined outside of the component’s class. There’s also no built-in way for the template to reference the current state of the component. This becomes a cumbersome limitation as the complexity of a component grows.</p>
<p>In the world of frontend, components are designed to help developers reuse markup in several pages. As a result, the markup and the component logic are inextricably linked, and so they should be colocated with one another.</p>
<h3 id="heading-writing-a-web-component-requires-understanding-all-of-its-underlying-technologies">Writing a web component requires understanding all of its underlying technologies</h3>
<p>As we saw above, web components are made up of three technologies. You can also see in the hello world code snippet, that we explicitly need to know and understand these three technologies.</p>
<ol>
<li>We’re creating a <strong>template element</strong> and setting its inner HTML</li>
<li>We’re creating a <strong>shadow root</strong>, and explicitly setting its mode to ‘open’.</li>
<li>We’re cloning our <strong>template</strong> and appending it to our <strong>shadow root</strong></li>
<li>We’re registering a new <strong>custom element</strong> to the document</li>
</ol>
<p>There’s nothing inherently wrong with this, since web components are supposed to be a “lower-level” browser API, making them prime for building abstractions on top of. But for a developer coming from a React or a Svelte background, having to understand these new browser features, and then having to write components with them can feel like too much friction.</p>
<h2 id="heading-more-advanced-web-components">More Advanced Web Components</h2>
<p>Let’s take a look at a more advanced web component, a counter button.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/11/counter-button.png" alt="A simple counter button. There's a clickable button, and some text showing how many times the button has been clicked" width="600" height="400" loading="lazy"></p>
<p>You click the button, and the counter increments.</p>
<p>The following example contains a few extra web component concepts, like lifecycle functions and observable attributes. You don’t need to understand everything going on in the code snippet. This example is really only used to illustrate how much boilerplate is required for the most basic of interactive interfaces, a counter button:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> templateEl = <span class="hljs-built_in">document</span>.createElement(<span class="hljs-string">"template"</span>);

templateEl.innerHTML = <span class="hljs-string">`
&lt;button&gt;Press me!&lt;/button&gt;
&lt;p&gt;You pressed me 0 times.&lt;/p&gt;
`</span>;

<span class="hljs-keyword">export</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">OdysseyButton</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">HTMLElement</span> </span>{
  <span class="hljs-keyword">constructor</span>() {
    <span class="hljs-built_in">super</span>();
    <span class="hljs-built_in">this</span>.attachShadow({ <span class="hljs-attr">mode</span>: <span class="hljs-string">"open"</span> });
    <span class="hljs-built_in">this</span>.shadowRoot.appendChild(templateEl.content.cloneNode(<span class="hljs-literal">true</span>));
    <span class="hljs-built_in">this</span>.button = <span class="hljs-built_in">this</span>.shadowRoot.querySelector(<span class="hljs-string">"button"</span>);
    <span class="hljs-built_in">this</span>.p = <span class="hljs-built_in">this</span>.shadowRoot.querySelector(<span class="hljs-string">"p"</span>);
    <span class="hljs-built_in">this</span>.setAttribute(<span class="hljs-string">"count"</span>, <span class="hljs-string">"0"</span>);
  }

    <span class="hljs-comment">// Note: Web components have lifecycle methods,</span>
  <span class="hljs-comment">// If we're setting event listeners when the component is added to the DOM, it's our job to clean</span>
  <span class="hljs-comment">// them up when it gets removed from the DOM</span>
  connectedCallback() {
    <span class="hljs-built_in">this</span>.button.addEventListener(<span class="hljs-string">"click"</span>, <span class="hljs-built_in">this</span>.handleClick);
  }

  disconnectedCallback() {
    <span class="hljs-built_in">this</span>.button.removeEventListener(<span class="hljs-string">"click"</span>, <span class="hljs-built_in">this</span>.handleClick);
  }

  <span class="hljs-comment">// Unlike frameworks like React, Web Components don't automatically rerender when a prop (or attribute)</span>
  <span class="hljs-comment">// changes. Instead, we need to explicitly define which attributes we want to observe.</span>
  <span class="hljs-keyword">static</span> <span class="hljs-keyword">get</span> <span class="hljs-title">observedAttributes</span>() {
    <span class="hljs-keyword">return</span> [<span class="hljs-string">"disabled"</span>, <span class="hljs-string">"count"</span>];
  }

  <span class="hljs-comment">// When one of the above attributes changes, this lifecycle method runs, and we can</span>
  <span class="hljs-comment">// react to the new attribute's value accordingly.</span>
  attributeChangedCallback(name, _, newVal) {
    <span class="hljs-keyword">if</span> (name === <span class="hljs-string">"count"</span>) {
      <span class="hljs-built_in">this</span>.p.innerHTML = <span class="hljs-string">`You pressed me <span class="hljs-subst">${newVal}</span> times.`</span>;
    }
    <span class="hljs-keyword">if</span> (name === <span class="hljs-string">"disabled"</span>) {
      <span class="hljs-built_in">this</span>.button.disabled = <span class="hljs-literal">true</span>;
    }
  }

  <span class="hljs-comment">// In HTML, attribute values are always strings. This means that it's our job to</span>
  <span class="hljs-comment">// convert types. You can see below that we're converting a string -&gt; number, and then back to a string</span>
  handleClick = <span class="hljs-function">() =&gt;</span> {
    <span class="hljs-keyword">const</span> counter = <span class="hljs-built_in">Number</span>(<span class="hljs-built_in">this</span>.getAttribute(<span class="hljs-string">"count"</span>));
    <span class="hljs-built_in">this</span>.setAttribute(<span class="hljs-string">"count"</span>, <span class="hljs-string">`<span class="hljs-subst">${counter + <span class="hljs-number">1</span>}</span>`</span>);
  };
</code></pre>
<p>As web component authors, we need to consider a lot of things:</p>
<ul>
<li>Setting up the shadow DOM</li>
<li>Setting up the HTML templates</li>
<li>Cleaning up event listeners</li>
<li>Defining properties that we want to observe</li>
<li>Reacting to properties when they change</li>
<li>Handling type conversions for attributes</li>
</ul>
<p>And there are still so many other things to consider that I haven’t touched on in this article.</p>
<p>That isn’t to say that web components are bad and that you shouldn’t write them. In fact, I’d argue that you learn so much about the browser platform by building with them. </p>
<p>But I feel that there are better ways to write components if your priority is to write interoperable components in a much more streamlined and ergonomic way.</p>
<h2 id="heading-how-to-write-web-components-with-less-boilerplate">How to Write Web Components with Less Boilerplate</h2>
<p>As I mentioned earlier, there are a lot of tools out there to help make writing web components much easier. </p>
<p>One such tool is called Lit, which is developed by a team at Google. <a target="_blank" href="https://lit.dev/">Lit</a> is a lightweight library designed to make writing web components simple, by removing the need for the boilerplate we’ve already seen above.</p>
<p>As we’ll see, Lit does a lot of heavy lifting under-the-hood to help cut down the total lines of code by nearly half! And because Lit is a wrapper around web components and other native browser features, all your existing knowledge about web components is transferable.</p>
<p>To start seeing how Lit simplifies your web components. Here’s the <strong>hello world</strong> example from earlier, but refactored to use Lit instead of a vanilla web component:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> { LitElement, html } <span class="hljs-keyword">from</span> <span class="hljs-string">"lit"</span>;

<span class="hljs-keyword">export</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">HelloWorld</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">LitElement</span> </span>{
  render() {
    <span class="hljs-keyword">return</span> html`<span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>Hello World!<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>`</span>;
  }
}<span class="hljs-string">`

customElements.define('hello-world', HelloWorld);</span>
</code></pre>
<p>There’s a lot less boilerplate with the Lit component, and Lit handles the two problems I mentioned earlier, a little bit differently. Let’s see how:</p>
<ol>
<li>The markup is directly defined from within the component class. While you can define your templates outside of the class, it’s common practice to return the template from the <code>render</code> function. This is more in line with the mental model presented in other UI frameworks, where the UI is a function of the state.</li>
<li>Lit also doesn’t require developers to attach the shadow DOM, or create templates and clone template elements. While having an understanding of the underlying web component features will help when developing Lit components, they’re not required for getting started, so the barrier for entry is much lower.</li>
</ol>
<p>So now for the big finale, what does the counter component look like once we’ve migrated it over to Lit?</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> { LitElement, html } <span class="hljs-keyword">from</span> <span class="hljs-string">"lit"</span>;

<span class="hljs-keyword">export</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">OdysseyCounter</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">LitElement</span> </span>{
  <span class="hljs-keyword">static</span> properties = {
        <span class="hljs-comment">// We define the component's properties as well as their type.</span>
        <span class="hljs-comment">// These properties will trigger the component to re-render when their values change.</span>
        <span class="hljs-comment">// While they're not the same, you can think of these "properties" as being</span>
        <span class="hljs-comment">// Lit's alternatives to "observed attributes"</span>
        <span class="hljs-comment">// If the value is passed down as an attribute, Lit converts the value</span>
        <span class="hljs-comment">// to the correct type</span>
    <span class="hljs-attr">count</span>: { <span class="hljs-attr">type</span>: <span class="hljs-built_in">Number</span> },
    <span class="hljs-attr">disabled</span>: { <span class="hljs-attr">type</span>: <span class="hljs-built_in">Boolean</span> },
  };

  <span class="hljs-keyword">constructor</span>() {
    <span class="hljs-built_in">super</span>();
        <span class="hljs-comment">// There's no need to create a shadow DOM, clone the template,</span>
        <span class="hljs-comment">// or store references to our DOM nodes.</span>
    <span class="hljs-built_in">this</span>.count = <span class="hljs-number">0</span>;
  }

  onCount() {
    <span class="hljs-built_in">this</span>.count = <span class="hljs-built_in">this</span>.count + <span class="hljs-number">1</span>;
  }

  render() {
        <span class="hljs-comment">// Instead of using the attributeChangedCallback lifecycle, the</span>
        <span class="hljs-comment">// render function has access to all of the component's properties,</span>
        <span class="hljs-comment">// which simplifies the process of manipulating our templates.</span>
    <span class="hljs-keyword">return</span> html`<span class="xml">
      <span class="hljs-tag">&lt;<span class="hljs-name">button</span> ?<span class="hljs-attr">disabled</span>=</span></span><span class="hljs-subst">${<span class="hljs-built_in">this</span>.disabled}</span><span class="xml"><span class="hljs-tag"> @<span class="hljs-attr">click</span>=</span></span><span class="hljs-subst">${<span class="hljs-built_in">this</span>.onCount}</span><span class="xml"><span class="hljs-tag">&gt;</span>
        Press me!
      <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>You pressed me </span><span class="hljs-subst">${<span class="hljs-built_in">this</span>.count}</span><span class="xml"> times.<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
    `</span>;
  }
}<span class="hljs-string">`</span>
</code></pre>
<p>The amount of code we’re writing is cut down by almost half! And this difference becomes more noticeable when creating more complex user interfaces.</p>
<h2 id="heading-why-am-i-going-on-about-lit">Why am I going on about Lit?</h2>
<p>I’m a big believer in web components, but I recognise that the barrier to entry is high for many developers. Writing complex web components requires understanding heaps of browser features and the education around web components isn’t as comprehensive as other technologies, like React or Vue.</p>
<p>This is why I think it’s important to use tools like Lit can make writing performant and interoperable web components much easier. This is great if you want your components to work within any frontend framework.</p>
<p>If you’d like to learn even more, this is the approach I teach in my upcoming course <a target="_blank" href="https://component-odyssey.com/">Component Odyssey</a>. This course is excellent for anyone who wants to understand how to write components that work in any framework. </p>
<p>I do this by covering the absolute basics of web components, before moving on to tools like Lit that simplify the process of writing web components without complicating your development environment. By the end, you’ll learn how to build and publish a component library that works across any frontend framework.</p>
<p>If you want early-bird discount codes for Component Odyssey, then head on <a target="_blank" href="https://component-odyssey.com/subscribe">over to the site to get notified</a>.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Write Helpful Error Messages to Improve Your App's User Experience ]]>
                </title>
                <description>
                    <![CDATA[ Gone are the days of useless and generic error messaging. Screenshot taken moments before a rage-quit If you're here, you're likely concerned with making your user-facing products as delightful as possible. And error messaging plays an important rol... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-write-helpful-error-messages-to-improve-your-apps-ux/</link>
                <guid isPermaLink="false">66bb8dfb3e3fa59ecfecb866</guid>
                
                    <category>
                        <![CDATA[ error handling ]]>
                    </category>
                
                    <category>
                        <![CDATA[ JavaScript ]]>
                    </category>
                
                    <category>
                        <![CDATA[ user experience ]]>
                    </category>
                
                    <category>
                        <![CDATA[ ux design ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Andrico Karoulla ]]>
                </dc:creator>
                <pubDate>Mon, 05 Apr 2021 22:07:00 +0000</pubDate>
                <media:content url="https://cdn-media-2.freecodecamp.org/w1280/60622fcb9618b008528a924c.jpg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Gone are the days of useless and generic error messaging.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/03/ykhg3yuzq8931--1-.png" alt="A generic error message displaying: &quot;Oops, something went wrong. Please try again later&quot;" width="600" height="400" loading="lazy">
<em>Screenshot taken moments before a rage-quit</em></p>
<p>If you're here, you're likely concerned with making your user-facing products as delightful as possible. And error messaging plays an important role in that. </p>
<p>Having useful error messages can go a long way toward making a frustrating scenario for an end-user as pleasant as possible.</p>
<p>This article is split into two parts. The first builds context around error messages and why they're important. This section should be useful, regardless of whether you're a JavaScript developer or not.</p>
<p>The second part is a short follow-along to help get you started managing your own error messages.</p>
<h2 id="heading-the-current-state-of-error-messaging"><strong>The current state of error messaging</strong></h2>
<p>In a perfect world, error messages would be redundant and users would be able to use anything you've built a-okay, no problem-o. But errors will happen, and your end-users will run into them. </p>
<p>These errors can stem from:</p>
<ul>
<li>Failing validation</li>
<li>Server-side failures</li>
<li>Rate limiting</li>
<li>Borked code</li>
<li>Acts of god</li>
</ul>
<p>And when things go wrong, often the client-facing error messaging takes shape in one of two ways:</p>
<ul>
<li>Generic errors with no meaningful information, e.g. <code>Something went wrong, please try again later</code></li>
<li>Hyper specific messages from the stack trace sent by the server, e.g. <code>Error 10x29183: line 26: error mapping Object -&gt; Int32</code></li>
</ul>
<p>Neither are helpful for our end-users.</p>
<p>For our users, the generic error can create a feeling of helplessness and frustration. If they get such a message, they can't complete an action, and have no way of knowing why the error happened and how (or if) they can resolve it. This can result in loss of end-user trust, loss of customer, or an angry review.</p>
<p>On the other hand, hyper-specific error messages are a leaky abstraction and shouldn't be seen by our end-user's eyes.</p>
<p>For one, these kind of errors provide implementation information about our server-side logic. Is this a security concern? probably? I'm no pen-tester.</p>
<p>Secondly, if we're in the business of crafting engaging user experiences, (and why wouldn't you be?) our error messages should feel human and be service-oriented. This is a sentiment shared in a number of resource I've come across, many of which of I've included in a further reading section at the end.</p>
<h2 id="heading-why-should-i-create-sane-error-messaging"><strong>Why should I create sane error messaging?</strong></h2>
<h3 id="heading-to-help-maintain-developer-sanity">To help maintain developer sanity</h3>
<p>Hunting bugs is hard, and scanning logs is tedious. Sometimes we're provided with context about why things failed, and other times we aren't. If an end-user reports a bug it's important they can present to us as much useful information as possible.</p>
<p>A report from a user that says:</p>
<p><code>Hi, I was using the app sometime last night updating my profile and all of a sudden it stopped working. The error said something about a validation error, but I don't know what that means</code></p>
<p>is much less useful than:</p>
<p><code>Hi, I was using the app sometime last night updating my profile and all of a sudden it stopped working. The error said "We had trouble updating your details. Your address must be located within the EU" but I live in England</code></p>
<p>This saves us time and cuts down on red herrings. A clear and specific error message may also help an end-user understand what they themselves have done wrong, and can allow them to fix their mistake.</p>
<h3 id="heading-to-help-maintain-organisation-sanity">To help maintain organisation sanity</h3>
<p>Sane error messages also yield benefits on an organisation level. For those working in larger companies, copy/messaging may be the responsibility of an entirely separate department. The more places in the code that require copy changes, the easier it is for the copy to get out of sync with your company's brand guidelines. </p>
<p>Conversely, keeping all of your error messages in a single source makes it much easier for those owning copy to adhere to those brand guidelines.</p>
<p>Other departments, like the support team, may be inundated with support tickets from users. If you're an engineer, why not reach out to your support team to see how many support tickets could be avoided with improved error messaging. </p>
<p>Fixing the problems with your messaging when a user incorrectly fills out a form, has missing data, or doesn't have permissions for a specific action could positively impact the lives of the support team.</p>
<h3 id="heading-to-help-maintain-end-user-sanity">To help maintain end-user sanity</h3>
<p>By providing sane error messaging we hope to not leave our end users feeling helpless. </p>
<p>As described earlier, our messaging should be <em>service</em>-<em>oriented</em>. They should guide our user on how to complete their process, or at least let them know where they can go and get help if the problem is beyond their control.</p>
<p>In Jon Yablonski's book, the Laws of UX, he describes a psychological concept called the Peak-end Rule:</p>
<blockquote>
<p><em>People judge an experience largely based on how they felt at its peak and at its end rather than the total sum or average of every moment of the experience</em></p>
</blockquote>
<p>In the context of this article, if people become so frustrated that they rage quit your site, their lasting memory of your application is of how frustrating it is to use. </p>
<p>Error messages play a large part in preventing this, as they can act as the final gatekeeper preventing a user who is simply stuck from turning to one so frustrated they quit your app.</p>
<p>If someone is using your product for a transactional purpose like buying an airplane ticket or shopping online, and they've been stopped dead in their tracks during a task with no way to continue, the likelihood of them leaving your site for another skyrockets. Another lost customer.</p>
<p>While this is wholly anecdotal, I've rage quit sites often from not knowing how to complete a process – either nothing happened when I clicked a button, or I just kept getting vague error messages. </p>
<p>Unless these sites/apps are one of those few ubiquitous platforms (like Google, Instagram, Apple), I likely haven't have used them since. I'm sure you can even remember a time this happened to you. In fact, I'll openly welcome pictures of awful error messages via <a target="_blank" href="https://twitter.com/andricokaroulla?lang=en">Twitter</a></p>
<p>Using sane error messaging can help offset this frustration if something doesn't go right. Surprisingly, creating a useful error message only requires a handful of qualities.</p>
<h2 id="heading-what-makes-a-good-error-message">What makes a good error message?</h2>
<p>Taken from <a target="_blank" href="https://www.microcopybook.com/">Microcopy: A complete guide</a>. A useful error message should satisfy these qualities:</p>
<ul>
<li>Explain clearly that there is a problem</li>
<li>Explain what the problem is</li>
<li>If possible, provide a solution so that the user can complete the process, or</li>
<li>Point them to where they can go for help</li>
<li>Make a frustrating scenario as pleasant as possible</li>
</ul>
<p>This might sound like a lot to cover with just a couple of sentences, but here are some examples of what I deem to be good error messages:</p>
<ul>
<li>We've limited how many times you can reset your password every hour. You can try again later.</li>
<li>Please log in to view this profile</li>
<li>We couldn't create your profile, only UK residents can use our app.</li>
</ul>
<p>It's worth noting that I'm not a UX researcher/designer, just a frontend developer with a keen interest in UX. It may be that my above examples miss the mark on what's required within your project or organisation. </p>
<p>Saying that, if you're a frontend engineer, improving your organisation's error messaging makes for an excellent opportunity to upskill and collaborate with your UXer colleagues.</p>
<h2 id="heading-how-can-i-start-writing-sane-error-messages">How can I start writing sane error messages?</h2>
<p>I've open-sourced a simple tool called <code>sane-error-messages</code>. Running the tool will generate a brand new repo designed to house your default error messaging. You can tweak the default values, add or remove messages, and then publish it to consume within your client facing apps.</p>
<p><code>sane-error-messages</code> works by aggregating all of your messaging in to a single JavaScript object. The key is an error code, and the value is a corresponding message. </p>
<p>The error codes should be the same codes you receive from your server, such as  <code>POSTS_NOT_FOUND</code> or <code>CONFLICTING_USER_RECORD</code>. Your error messaging repo exposes a function to get your error message from an error code. </p>
<p>This approach was inspired by how tools like <a target="_blank" href="https://www.freecodecamp.org/news/p/009d4c55-b3e6-4e48-b186-541f5959af8c/*https://github.com/cypress-io/cypress/blob/develop/packages/server/lib/errors.js*">Cypress</a> handle their error messaging.</p>
<p>As long as your server returns predictable error codes, the server-side implementation doesn't matter. The following sequence is just one way of implementing <em><code>sane-error-messages</code></em></p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/03/Screenshot-2021-03-15-at-21.41.28.png" alt="A sequence diagram showing the process of displaying a sane error message." width="600" height="400" loading="lazy">
<em>Having a separate repo becomes more important the more user-facing apps you have.</em></p>
<p>In short:</p>
<ul>
<li>The user "views all products"</li>
<li>The frontend makes a network request</li>
<li>The network request fails and returns an error code "USER_NOT FOUND"</li>
<li>The frontend requests the corresponding error message from your <code>error-messages</code> package.</li>
<li>The frontend applies any relevant contextual information</li>
<li>The frontend displays this information to the end user.</li>
</ul>
<p>If you want to try something hands on, you can play with this <a target="_blank" href="https://codesandbox.io/s/amazing-platform-dxtjc?file=/src/App.js">CodeSandbox</a>. The CodeSandbox fires off a request to a mock server which returns 1 of 12 error codes at random. </p>
<p>The client side will use the error code to retrieve a sane error message from the error messages repo. The client side then displays the error message to the user. If the code doesn't have a specified message, the generic fallback gets shown (and it sucks).</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/03/ezgif.com-gif-maker--2-.gif" alt="A gif of relevant error messages displaying on a code sandbox" width="600" height="400" loading="lazy">
<em>Some sane error messages in the wild</em></p>
<h2 id="heading-how-to-set-up-your-error-messages">How to set up your error messages</h2>
<p>Note: You can find the <a target="_blank" href="https://github.com/andrico1234/sane-error-messages#readme">repo here</a>. If you come across any problems during the tutorial process you can file a GitHub issue.</p>
<p>Begin by running</p>
<p><code>yarn global add sane-error-message</code></p>
<p>then</p>
<p><code>sane-error-messages create &lt;dirName&gt;</code></p>
<p>to scaffold your project. Doing so will create a brand new module for you to customise with your default error messages. </p>
<p>Your new module uses <code>tsdx</code> under-the-hood to handle all of the module management scripts, such as running, building, and testing.</p>
<p>You can learn more about <a target="_blank" href="https://www.freecodecamp.org/news/p/009d4c55-b3e6-4e48-b186-541f5959af8c/*https://tsdx.io/*">tsdx here</a>.</p>
<p>In short, the contents of your new package will look like this:</p>
<pre><code class="lang-typescript"><span class="hljs-comment">/* errorCodes.ts: The file that defines each error code like */</span>
<span class="hljs-keyword">const</span> USER_NOT_ADMIN = <span class="hljs-string">'403_USER_NOT_ADMIN'</span>

<span class="hljs-comment">/* defaultErrorMessages.ts: Maps each code to a default message */</span>
<span class="hljs-keyword">const</span> errorCodes {
  <span class="hljs-comment">// your codes and messages go here...</span>
  [USER_NOT_ADMIN]: <span class="hljs-string">"We're afraid only administrators have access to "</span>
}

<span class="hljs-comment">/* ErrorMessages.ts: The class you'll use to instantiate your error messages object in the consuming project */</span>
<span class="hljs-keyword">class</span> ErrorMessages {
  <span class="hljs-comment">// You can override default messages with more specific ones</span>
  <span class="hljs-keyword">constructor</span>: (<span class="hljs-params">customErrorMessages: Partial&lt;Record&lt;<span class="hljs-built_in">string</span> | <span class="hljs-built_in">number</span>, <span class="hljs-built_in">string</span>&gt;&gt;</span>): ErrorMessages;

  <span class="hljs-comment">// Pass through an error code to get your custom message</span>
  getErrorMessage: (code: <span class="hljs-built_in">string</span> | <span class="hljs-built_in">number</span>, fallbackMessage?: <span class="hljs-built_in">string</span>): <span class="hljs-built_in">string</span>;

  <span class="hljs-comment">// Checks to see if the argument is a valid error code and acts as a guard for non-ErrorCode values</span>
  isErrorCode(code: <span class="hljs-built_in">string</span> | <span class="hljs-built_in">number</span>): <span class="hljs-built_in">boolean</span>;

  <span class="hljs-comment">// Returns the errorCodes object with your custom messages</span>
  messages: Record&lt;ErrorCode, <span class="hljs-built_in">string</span>&gt;
}

<span class="hljs-keyword">type</span> ErrorCode = ValueOf&lt;errorCodes&gt;
</code></pre>
<h2 id="heading-how-to-consume-your-error-messages">How to consume your error messages</h2>
<p>If you created a repo with the name <code>custom-error-messages</code> and published it to npm, you'd be able to consume it within your apps by doing the following:</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">import</span> { ErrorMessages } <span class="hljs-keyword">from</span> <span class="hljs-string">'custom-error-messages'</span>;

<span class="hljs-keyword">const</span> customErrorMessages = {
  <span class="hljs-string">'400_validation'</span>: <span class="hljs-string">'Please enter the fields in your form correctly'</span>,
};

<span class="hljs-comment">// Initialise your errorMessages object with your custom messages</span>
<span class="hljs-keyword">const</span> errorMessages = <span class="hljs-keyword">new</span> ErrorMessages(customErrorMessages);

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">riskyFunction</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">try</span> {
    <span class="hljs-comment">// Throws an error </span>
    <span class="hljs-keyword">await</span> boom();
  } <span class="hljs-keyword">catch</span> (err) {
    <span class="hljs-comment">// Get the error code our server sent over</span>
    <span class="hljs-keyword">const</span> { code } = err;

    <span class="hljs-comment">// Get the code's corresponding message</span>
    <span class="hljs-keyword">const</span> message = errorMessages.getErrorMessage(code);

    <span class="hljs-comment">// Display the message to the client</span>
    displayNotification(message);
  }
}
</code></pre>
<p>You can then take all of the error codes that your server-side returns and apply corresponding messages to them.</p>
<p>Once you're ready, you can publish your tool to NPM, and then consume it from your client-facing apps.</p>
<h2 id="heading-conclusion"><strong>Conclusion</strong></h2>
<p>I hope you've enjoyed learning about an often overlooked aspect of web development. </p>
<p>I've done a bunch of reading to learn about error messaging and I've shared some of my favourite resources below. Some are books and others are short articles, but they're all worth your time.</p>
<p>You can also reach out if any part of the tutorial wasn't clear, or if you feel I can streamline things. Thanks for reading.</p>
<h2 id="heading-faqs">FAQs</h2>
<h3 id="heading-why-cant-the-server-side-just-return-these-messages">Why can't the server-side just return these messages?</h3>
<p>The server shouldn't be concerned with any client-facing logic. But if you're fortunate enough to work with an API that gives useful error codes with each failed request, then you're nearly there.</p>
<h3 id="heading-will-i-need-to-create-an-instance-of-error-messages-for-every-api-consumer">Will I need to create an instance of error-messages for every API consumer?</h3>
<p>Not necessarily. Because this package can take a list of default messages and codes, as long as it's in sync with the APIs, your frontends will be able to consume the same package. </p>
<p>In each client-side instance, you can pass through additional error codes, or override existing messages to tailor your frontend messaging.</p>
<h3 id="heading-i-think-this-package-should-have-x-or-do-y-differently">I think this package should have X or do Y differently</h3>
<p>I'm dogfooding this internally at my job, and this is a problem space I'm very new to. I would love to hear of any suggestions, or improvements to the overall architecture or feature-set of <em><code>sane-error-messages</code>.</em></p>
<h2 id="heading-further-reading"><strong>Further Reading</strong></h2>
<p><strong>Microcopy: A Complete Guide</strong><br>I mentioned this book a little earlier, and it's one of my favourites when it comes to making my user-facing products a lot more personable.</p>
<p>The book's author Kinneret Yifrah, has graciously provided a coupon for 10% off, you can purchase it <a target="_blank" href="https://www.microcopybook.com/">here</a>.</p>
<p>Coupon code for the eBook: andrico-ebook</p>
<p>Coupon code for the bundle: andrico-bundle</p>
<p><strong>Error messaging guidelines: NN Group</strong><br>A <a target="_blank" href="https://www.nngroup.com/articles/error-message-guidelines/">short article</a> on the importance of sane error messaging which shares some very useful tips on how to create sane error messaging.</p>
<p>In short:</p>
<ul>
<li>Errors should be expressed in plain language</li>
<li>Indicate what the problem is</li>
<li>Suggest a solution</li>
</ul>
<p><strong>Error Messages (Design basics): Microsoft</strong><br>An <a target="_blank" href="https://docs.microsoft.com/en-us/windows/win32/uxguide/mess-error">in-depth article</a> that covers both design guidelines messaging practices</p>
<p><strong>Laws of UX</strong><br>A <a target="_blank" href="https://www.amazon.co.uk/gp/product/149205531X/ref=as_li_tl?ie=UTF8&amp;camp=1634&amp;creative=6738&amp;creativeASIN=149205531X&amp;linkCode=as2&amp;tag=calistheni02b-21&amp;linkId=3f089ce27d59c4eeb48522be9ac52fb2">short book</a> that introduces how a handful of psychology concepts can be used to improve your products UX.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ beautiful-skill-tree is officially v1! ? ]]>
                </title>
                <description>
                    <![CDATA[ Visualise a satisfying feeling of progression in your app with the help of beautiful-skill-tree. What is beautiful-skill-tree? ? beautiful-skill-tree came about as as result of my love for video games, web development and fitness. BST was never inten... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/beautiful-skill-tree-is-officially-v1/</link>
                <guid isPermaLink="false">66bb8df5d2bda3e4315491bb</guid>
                
                    <category>
                        <![CDATA[ Design ]]>
                    </category>
                
                    <category>
                        <![CDATA[ JavaScript ]]>
                    </category>
                
                    <category>
                        <![CDATA[ React ]]>
                    </category>
                
                    <category>
                        <![CDATA[ TypeScript ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Web Design ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Web Development ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Andrico Karoulla ]]>
                </dc:creator>
                <pubDate>Wed, 13 Nov 2019 15:07:07 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2019/11/jeremy-bishop-EwKXn5CapA4-unsplash.jpg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Visualise a satisfying feeling of progression in your app with the help of beautiful-skill-tree.</p>
<h1 id="heading-what-is-beautiful-skill-tree">What is beautiful-skill-tree? ?</h1>
<p><a target="_blank" href="https://github.com/andrico1234/beautiful-skill-tree">beautiful-skill-tree</a> came about as as result of my love for video games, web development and fitness. BST was never intended to be a standalone package, but a feature in a <a target="_blank" href="https://calisthenicsskills.com/">fitness progress app</a>. After discovering that there were no easy-to-use libraries that empower developers to create their own versatile skill trees, BST ended up manifesting as exactly that.</p>
<p>My key motivation for beautiful-skill-tree is to create a package that can be used across a series of browsers and devices, with interactions that feel intuitive, sleek, and gratifying. </p>
<p>While developer experience was a major consideration when creating BST, I wanted usability to be BST's key measurement for success. Thanks to tools like <a target="_blank" href="https://www.browserstack.com/">Browserstack</a>, BST has been tested and validated across a series of operating systems, browsers and devices. And thanks to my friends, family (incl. my grandmother), coworkers, and strangers in ensuring that it has been tested across a diverse range of people.</p>
<h1 id="heading-what-can-i-do-with-beautiful-skill-tree">What can I do with beautiful-skill-tree? ?</h1>
<p>Currently, the most comprehensive use of beautiful-skill-tree in the wild is <a target="_blank" href="https://calisthenicsskills.com/">Calisthenics Skills</a>.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2019/11/ezgif.com-video-to-gif.gif" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Setting up BST in your own application is straightforward, with the official <a target="_blank" href="https://github.com/andrico1234/beautiful-skill-tree/blob/master/README.md">README</a> guiding you through the key features in great detail.</p>
<p>Once you've imported the components and configured the <code>SkillTree</code>, all that's left is to supply your own data. For those, like myself, who are TypeScript nerds, BST exports types to ensure that your data adheres to the structure required. If usability is my bottom-line measure for success, developer experience places a close second.</p>
<p>Here's what beautiful-skill-tree offers you:</p>
<ul>
<li>? A way to visualise user progression in your application</li>
<li>?️ Responsive, cross-browser compatible trees</li>
<li>?️ Silky smooth animations</li>
<li>⌨️ Keyboard navigable trees</li>
<li>? Collapsible trees</li>
<li>? Custom theming</li>
<li>? Saving to localstorage out-of-the-box</li>
<li>✍? Option to implement custom saving</li>
<li>❓ Optional nodes</li>
<li>? Access to your tree's data and methods</li>
</ul>
<h1 id="heading-what-can-i-expect-beyond-v1">What can I expect beyond v1? ?</h1>
<ul>
<li>Custom pre-requisites to to unlock/select skills</li>
<li>Searching/Filtering through trees and skills</li>
<li>Features as a result of insight received from feedback</li>
</ul>
<p>In the future, I'll talk about some of the challenges I've come across during the creation and development of BST, and the User Experience lessons I've learnt along the way. Stay tuned!</p>
<p>And a big thanks to everyone that has used beautiful-skill-tree in the past!</p>
<hr>
<p>Have you used beautiful-skill-tree in your own project? You can leave anonymous feedback and feature suggestions <a target="_blank" href="https://docs.google.com/forms/d/e/1FAIpQLSfQ5cJSMt4nLTVsXP88_0EfPXbzSwHoJlzWRW5nBWKNMtKSHA/viewform?usp=sf_link">here</a>. You can try it out here</p>
<p>If you're interested in keeping up-to-date with any of my projects you can find me in the following places:</p>
<ul>
<li><a target="_blank" href="https://www.instagram.com/andricokaroulla/?hl=en">Instagram</a></li>
<li><a target="_blank" href="https://github.com/andrico1234">Github</a></li>
<li><a target="_blank" href="https://twitter.com/andricokaroulla?lang=en">Twitter</a></li>
<li><a target="_blank" href="https://www.freecodecamp.org/news/author/andrico/">freeCodeCamp</a></li>
<li><a target="_blank" href="https://medium.com/@andricokaroulla">Medium</a></li>
</ul>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to create a Borderlands-style skill tree in 5 minutes ]]>
                </title>
                <description>
                    <![CDATA[ Growing up, I spent my spare time doing what most programmers did: played video games every waking moment. I loved Adventure games and what a time sink they were. If time was the Mary Rose, and I was the French, my artillery were games like Kingdom H... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/create-a-borderlands-style-skill-tree-in-5-minutes/</link>
                <guid isPermaLink="false">66bb8df85d242388375d3872</guid>
                
                    <category>
                        <![CDATA[ JavaScript ]]>
                    </category>
                
                    <category>
                        <![CDATA[ React ]]>
                    </category>
                
                    <category>
                        <![CDATA[ TypeScript ]]>
                    </category>
                
                    <category>
                        <![CDATA[ User Interface ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Video games ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Andrico Karoulla ]]>
                </dc:creator>
                <pubDate>Tue, 01 Oct 2019 14:00:00 +0000</pubDate>
                <media:content url="https://cdn-media-2.freecodecamp.org/w1280/5f9ca02c740569d1a4ca4706.jpg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Growing up, I spent my spare time doing what most programmers did: played video games every waking moment. I loved Adventure games and what a time sink they were. If time was the Mary Rose, and I was the French, my artillery were games like Kingdom Hearts, Ōkami, and Borderlands.</p>
<p>Why did I, and others, spend so much of our spare time exploring, surviving, dying, and (so, so much) grinding? Hundreds of factors contribute toward making an engaging experience, but the one I’m going to focus on is the notion of progression.</p>
<p>The idea of gamification isn’t new. Many popular applications (like <a target="_blank" href="https://todoist.com/?lang=en">todoist</a>, or <a target="_blank" href="https://productivitychallengetimer.com/">challenge timer</a>) have incorporated some sort of progression scheme to make us, the consumers, use their app, give them money, and hand over our personal data. So I decided to go about my way of enabling others to do just that, through beautiful skill trees! Note: I expect neither money nor data from those using my skill trees.</p>
<p>The last few weeks have seen me toil away to create what I hope to be a pleasant plug’n’play React package to help you create exciting skill trees. You can test it yourself by following the tutorial. I hope it will be a frictionless experience.</p>
<p>We hope to have something resembling the skill tree below:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2019/10/image-2.png" alt="Image" width="600" height="400" loading="lazy">
<em>“A dying puppy. A baby in tears. If the previous statements elicited any emotional reaction report to your supervisor for summary destruction.”</em></p>
<h1 id="heading-beautiful-skill-tree075">beautiful-skill-tree@0.7.5</h1>
<p>Grab the starter repo by using <code>git clone git@github.com:andrico1234/borderlands-skill-tree.git</code></p>
<p>Move into the directory and run the starting script, <code>yarn start</code>. Give the site a whirl, you'll see nothing but the Borderlands logo and environment.</p>
<p><code>beautiful-skill-tree</code> exposes three components: the <code>SkillProvider</code>, <code>SkillTreeGroup</code>, and the <code>SkillTree</code> components.</p>
<p><code>SkillProvider</code>: This takes in no props and supplies the children with the skill tree's context. This puppy handles all of the global data related to the skill tree.</p>
<p><code>SkillTreeGroup</code>: Is more involved in that it can take an optional <code>theme</code> property, where we can pass in some custom styling, to make our skill tree feel very Borderlands. The <code>SkillTreeGroup</code> also uses the children-as-a-function pattern to give us access to some imperative api functionality, such as skill tree reset, selected skills counter, etc. We don't need to worry about any of those for the scope of this article.</p>
<p><code>SkillTree</code>: This is the most exciting of the package's exports, unless you're a sucker for typings (which are also exported, for all you TS fans). The <code>SkillTree</code> doesn't take any children but requires 3 props: <code>treeId</code>, <code>title</code>, and <code>data</code>. The <code>treeId</code> should be an id that's unique to each skill tree, but should be persistent across user sessions as this is used as the key for getting and setting the data to local storage. I'm not going to explain what the <code>title</code> prop does, I'll leave you to experiment. The <code>data</code> is the mixing pot of the application. You'll pass in your skill tree data structure which the app will use to render a <code>beautiful-skill-tree</code>. Let's get a real basic tree going before we move on to our multi-tree, multi-branch Borderlands spectacular.</p>
<p>In App.tsx, import the 3 components like so:</p>
<p><code>import { SkillProvider, SkillTreeGroup, SkillTree } from 'beautiful-skill-tree';</code></p>
<p>Place it underneath your <code>img</code> tag, outside of the image's container div, but within the outer div. Add the <code>SkillProvider</code>, passing the <code>SkillTreeGroup</code> as a child. Before you do the same with the <code>SkillTree</code>, remember that as <code>SkillTreeGroup</code> uses function-as-a-child pattern, you'll need to render a function that returns the child components. Return a single <code>SkillTree</code> and give it a <code>treeId</code> and a <code>title</code> prop. Pass an empty array into the <code>data</code> prop so your <code>App.tsx</code> looks like this:</p>
<pre><code class="lang-js"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">App</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>
    // <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">headercontent</span> /&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">SkillProvider</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">SkillTreeGroup</span>&gt;</span>
          {() =&gt; {
            return (
              <span class="hljs-tag">&lt;<span class="hljs-name">SkillTree</span> <span class="hljs-attr">treeId</span>=<span class="hljs-string">"basic-birch"</span> <span class="hljs-attr">title</span>=<span class="hljs-string">"First Skill Tree"</span> <span class="hljs-attr">data</span>=<span class="hljs-string">{[]}</span> /&gt;</span>
            )
          }}
        <span class="hljs-tag">&lt;/<span class="hljs-name">SkillTreeGroup</span>&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">SkillProvider</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  );
}
</code></pre>
<p>Go to <a target="_blank" href="http://localhost:3000/">localhost:3000</a> to see the application running. You should see the logo, background, and a grey rectangle. If you’re running into any errors, go through the introduction again and check to see if there any syntax error or incorrect imports.</p>
<p>Next, let’s create a real basic tree. Just 3 items that move in a linear line. The data structure for <code>data</code> looks like this:</p>
<pre><code class="lang-ts"><span class="hljs-keyword">type</span> Skill = {
  id: <span class="hljs-built_in">string</span>;
  icon?: <span class="hljs-built_in">string</span>;
  title: <span class="hljs-built_in">string</span>;
  tooltip: {
    description : <span class="hljs-built_in">string</span>;
  },
  children: Skill[];
}
</code></pre>
<p>Each skill requires four properties, with one being optional. You should also notice that the <code>children</code> property is a recursive type, meaning that it takes an array of the same data structure, which it uses to render the children of the skill. This can go on infinitely, and make for some real complicated, winding trees. I'll create the first skill for you, and I'll trust you with carrying on for the next two items.</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> data = [{
  <span class="hljs-attr">id</span>: <span class="hljs-string">'first-skill'</span>,
  <span class="hljs-attr">title</span>: <span class="hljs-string">'The root node'</span>,
  <span class="hljs-attr">tooltip</span>: {
    <span class="hljs-attr">description</span> : <span class="hljs-string">"The parent node, all of the descendants will be locked until it's selected"</span>,
  },
  <span class="hljs-attr">children</span>: [
  <span class="hljs-comment">// rinse and repeat; always repeat.</span>
]}
</code></pre>
<p>Add the above snippet to the <code>App.tsx</code> file, and replace the empty array inside of the <code>SkillTree</code>'s <code>data</code> property with our <code>data</code> definition. Load your page, and you should have an interactive node. Give it a hover and a click and it should be reacting to your actions. If things are working, then I'll task you with creating two (or more) child nodes. Experiment with children and sibling lengths, to see what you can come up with. (If you also happen to break my precious package, leave me a GitHub issue so I can patch things up).</p>
<p>Once you’re comfortable with creating a skill tree, let’s go ahead and create our Borderlands skill tree. Fortunately, I’ve done all of the tedious work for you and have already created the data structures and accumulated the images.</p>
<p>You’ll need to import the three trees from the <code>data</code> file, which can be done via</p>
<p><code>import { motion, harmony, cataclysm } from "./data/data";</code></p>
<p>The next step is creating two additional <code>SkillTrees</code> alongside the current one. You'll need to wrap them in a <code>React.Fragment</code> as your <code>SkillTreeGroup</code> will now be trying to render 3 top level components. Pass in the data accordingly, and if you're unsure, I've posted the code snippet below.</p>
<pre><code class="lang-js">&lt;React.Fragment&gt;
  <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">SkillTree</span> <span class="hljs-attr">treeId</span>=<span class="hljs-string">"motion"</span> <span class="hljs-attr">title</span>=<span class="hljs-string">"Motion"</span> <span class="hljs-attr">data</span>=<span class="hljs-string">{motion}</span> /&gt;</span></span>
  <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">SkillTree</span> <span class="hljs-attr">treeId</span>=<span class="hljs-string">"harmony"</span> <span class="hljs-attr">title</span>=<span class="hljs-string">"Harmony"</span> <span class="hljs-attr">data</span>=<span class="hljs-string">{harmony}</span> /&gt;</span></span>
  <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">SkillTree</span> <span class="hljs-attr">treeId</span>=<span class="hljs-string">"cataclysm"</span> <span class="hljs-attr">title</span>=<span class="hljs-string">"Cataclysm"</span> <span class="hljs-attr">data</span>=<span class="hljs-string">{cataclysm}</span> /&gt;</span></span>
&lt;/React.Fragment&gt;
</code></pre>
<p>Go ahead and check your web browser, it should be <strong>aaallmoost</strong> ready. We’ve got the skills rendered, but the styling feels a little lackluster. It doesn’t feel very Borderlands. Fortunately for you, I’m a regular <a target="_blank" href="https://www.youtube.com/watch?v=0evlWSY8kTc">Neil Buchanan</a> and prepared a custom theme. Import the theme and pass it through to the <code>SkillTreeGroup</code>'s <code>theme</code> prop. The theme object is export via <code>import theme from './data/theme';</code>. Easy!</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2019/10/image-3.png" alt="Image" width="600" height="400" loading="lazy">
<em>“I HAVE ONE QUESTION FOR YOU. EXPLOSIONS?”</em></p>
<p>Once you’ve done the above, check out the finished product. If you’re still not satisfied with the styles, check out the theme object and customise it yourself, there are a bunch of additional attributes whose styles can be adjusted, so just peek into the typings of the package.</p>
<p>I mentioned earlier that there are a few additional properties and values that can be used to tweak the skill tree, so have a mess around yourself, and link me to any cool trees you create. I’d love to add it to the growing list of trees found <a target="_blank" href="https://github.com/andrico1234/beautiful-skill-tree#examples">here</a>. <a target="_blank" href="https://calisthenicsskills.com/">Here’s</a> an example of the skill tree that kickstarted this obsession.</p>
<p>I hope you’ve enjoyed tinkering with the <code>beautiful-skill-tree</code> package. I'm always adding new features and updating, so give it a star on github! You can find an online demo of the borderlands skill tree <a target="_blank" href="http://borderlands-skill-tree.s3-website.eu-west-2.amazonaws.com/">here</a></p>
<p>You can find me on Instagram or GitHub if you want to chat code, music, or fitness!</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ My favorite way to keep programming when I’m traveling or don’t have internet ]]>
                </title>
                <description>
                    <![CDATA[ This is a short guide on sharpening your skills and keeping productive when in transit. And it doesn’t involve burying your face in a book. Books can only get you so far Now don’t get me wrong, I love a good programming book. Jon Duckett’s series on ... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/my-favorite-way-to-keep-programming-when-im-traveling-or-don-t-have-internet-d1c2d26618b7/</link>
                <guid isPermaLink="false">66bb8dfe5d242388375d3874</guid>
                
                    <category>
                        <![CDATA[ JavaScript ]]>
                    </category>
                
                    <category>
                        <![CDATA[ personal development ]]>
                    </category>
                
                    <category>
                        <![CDATA[ General Programming ]]>
                    </category>
                
                    <category>
                        <![CDATA[ tech  ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Web Development ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Andrico Karoulla ]]>
                </dc:creator>
                <pubDate>Wed, 14 Nov 2018 17:32:46 +0000</pubDate>
                <media:content url="https://cdn-media-1.freecodecamp.org/images/0*5djL-YOSdGd_rK_x" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>This is a short guide on sharpening your skills and keeping productive when in transit. And it doesn’t involve burying your face in a book.</p>
<h3 id="heading-books-can-only-get-you-so-far">Books can only get you so far</h3>
<p>Now don’t get me wrong, I love a good programming book. Jon Duckett’s series on HTML, CSS, and JavaScript were the guiding beacons during my formative years as a Web Developer. Robert C Martin’s seminal tome Clean Code has its pages bent. It is misshapen through years of being wrung dry for each drop of information. Even Simon Holmes’ Getting MEAN, while now dated, had its time by my side in the local café. It was my companion as I created my first full-stack application.</p>
<p>With a little preparation, most of these books could’ve been used with no, or much more frighteningly, slow internet. Download the packages in advance. Get your local environments working. If the book’s comprehensive enough, you’ll likely make solid progress without needing Google, GitHub or StackOverflow.</p>
<p>On the flip-side, we as programmers thrive best when tasked with a challenge. Having an author walk us through solutions is nice, but it’s not enough. The best way for us to improve our problem-solving skills is to solve problems.</p>
<p>If you’re a professional programmer then you’re likely to be solving your fair share of problems on a day-to-day basis. If you’re a hobbyist then you might find pleasure from creating your own <a target="_blank" href="http://www.jsfuck.com/">JSF**k</a> applications. Or even killing time by solving algorithm challenges online. It’s why sites like CodeWars or HackerRank are so popular.</p>
<p>The underlying problem with most of these, particularly the latter, is continuing when the internet breaks. Or without connection to begin with. Both are common scenarios as developers are becoming more nomadic. How do you kill time during your 12-hour flight from London to Shanghai, while still reaping the rewards gained from solving problems?</p>
<p>I have had the displeasure of being on such a long flight. There’s about enough space on said flight to prop your laptop on the foldout tray. Everything beyond that becomes a game of Tetris, trying to make your comfort and possessions fit in the limited space given to you on your budget flight. So you’ve got your laptop, headphones, jumper, snacks, and water all within arms reach? It’s starting to feel cramped, right? Try pulling out your 600 page 2-kilo programming book. Yeah, not gonna happen.</p>
<h3 id="heading-the-silver-bullet">The silver bullet</h3>
<p>So how did I overcome this impediment? Well, I reimplemented the Lodash library.</p>
<p>Why did I choose a such an arbitrary task? There are many key reasons. Some I rationalized before taking on the challenge and others I discovered along the way. Here are some of the most notable:</p>
<ul>
<li>Each function feels like a miniature code challenge</li>
<li>The documentation is on a single HTML page, easy to download and view offline</li>
<li>It encourages looking inside the source code when stuck</li>
<li>It allows you to build your own suite of utility functions</li>
<li>It’s a library with no dependencies, which keeps things simple</li>
<li>You will get more familiar with your programming language of choice</li>
</ul>
<p>Let’s dive a bit more into each of these points.</p>
<h4 id="heading-each-function-feels-like-a-code-challenge"><strong>Each function feels like a code challenge</strong></h4>
<p>As I mentioned earlier on, Codewars and HackerRack are two very popular programming challenge sites. For those unfamiliar, you’re given a programming task to complete within the built-in text-editor. When completed, you run your finished code against the curated suite of tests. The aim of the challenge is to get all tests passing.</p>
<p>It’s not difficult emulating this yourself. If anything, it’s a great way of improving your approach to TDD (test driven development). My general approach to reimplementing a function would be to stub out the method:</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> concat = <span class="hljs-function">(<span class="hljs-params">arr, ...otherParams</span>) =&gt;</span> {
  <span class="hljs-comment">// if array is invalid throw error</span>

  <span class="hljs-comment">// handle no input for second parameter</span>

  <span class="hljs-comment">// add each item to a new array</span>
    <span class="hljs-comment">// flatten 1 level if item is array</span>

  <span class="hljs-comment">// return new array</span>
};
</code></pre>
<p>const concat = (arr, ...otherParams) =&gt; {  // if array is invalid throw error  // handle no input for second parameter  // add each item to a new array    // flatten 1 level if item is array  // return new array};</p>
<p>The next step is to create my test suite with some assertions I’d expect my function to satisfy:</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> concat = <span class="hljs-built_in">require</span>(<span class="hljs-string">'../concat'</span>);

describe(<span class="hljs-string">'concat'</span>, <span class="hljs-function">() =&gt;</span> {
  it(<span class="hljs-string">'should return the expect results with valid inputs'</span>, <span class="hljs-function">() =&gt;</span> {
    expect(concat([<span class="hljs-number">1</span>, <span class="hljs-number">2</span>], [<span class="hljs-number">1</span>], [<span class="hljs-number">2</span>], <span class="hljs-number">4939</span>, <span class="hljs-string">'DDD'</span>)).toEqual([<span class="hljs-number">1</span>, <span class="hljs-number">2</span>, <span class="hljs-number">1</span>, <span class="hljs-number">2</span>, <span class="hljs-number">4939</span>, <span class="hljs-string">'DDD'</span>]);
    expect(concat([], <span class="hljs-literal">null</span>, <span class="hljs-number">123</span>)).toEqual([<span class="hljs-literal">null</span>, <span class="hljs-number">123</span>]);
  });

  it(<span class="hljs-string">'should throw errors with invalid inputs'</span>, <span class="hljs-function">() =&gt;</span> {
    expect(<span class="hljs-function">() =&gt;</span> concat(<span class="hljs-number">23</span>, <span class="hljs-number">23</span>).toThrow(<span class="hljs-built_in">TypeError</span>));
    expect(<span class="hljs-function">() =&gt;</span> concat([<span class="hljs-number">1</span>, <span class="hljs-number">2</span>, <span class="hljs-number">3</span>], <span class="hljs-number">-1</span>).toThrow(<span class="hljs-built_in">TypeError</span>));
  });

  it(<span class="hljs-string">'should correctly handle strange inputs'</span>, <span class="hljs-function">() =&gt;</span> {
    expect(concat([<span class="hljs-number">111</span>], <span class="hljs-literal">null</span>, <span class="hljs-string">'rum ham'</span>)).toEqual([<span class="hljs-number">111</span>, <span class="hljs-literal">null</span>, <span class="hljs-string">'rum ham'</span>]);
  });
});
</code></pre>
<p>Then I’d implement the code so the tests run successfully:</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> { isValidArray } = <span class="hljs-built_in">require</span>(<span class="hljs-string">'../helpers'</span>);

<span class="hljs-keyword">const</span> concat = <span class="hljs-function">(<span class="hljs-params">arr, ...otherParams</span>) =&gt;</span> {
  <span class="hljs-keyword">if</span> (!isValidArray(arr)) <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">Error</span>(<span class="hljs-string">'Argument is not a valid array'</span>);

  <span class="hljs-keyword">if</span> (otherParams.length === <span class="hljs-number">0</span>) <span class="hljs-keyword">return</span> [];

  <span class="hljs-keyword">const</span> concatenatedArray = otherParams.reduce(<span class="hljs-function">(<span class="hljs-params">acc, item</span>) =&gt;</span> {
    <span class="hljs-keyword">if</span> (isValidArray(item)) <span class="hljs-keyword">return</span> [...acc, ...item];

    <span class="hljs-keyword">return</span> [...acc, item];
  }, [...arr]);

  <span class="hljs-keyword">return</span> concatenatedArray
};
</code></pre>
<p>Knocking out one of these functions will leave you with a sense pride and accomplishment.</p>
<h4 id="heading-simple-html-documentation"><strong>Simple HTML documentation</strong></h4>
<p>Most libraries have a GitHub page with an API reference. These are usually a single page of Markdown that’s available for download. Take a snippet from the Recompose library:</p>
<h3 id="heading-branch"><code>branch()</code></h3>
<pre><code class="lang-js">branch(
  test: <span class="hljs-function">(<span class="hljs-params">props: <span class="hljs-built_in">Object</span></span>) =&gt;</span> boolean,
  <span class="hljs-attr">left</span>: HigherOrderComponent,
  <span class="hljs-attr">right</span>: ?HigherOrderComponent
): HigherOrderComponent
</code></pre>
<p>Accepts a test function and two higher-order components. The test function is passed the props from the owner. If it returns true, the <code>left</code> higher-order component is applied to <code>BaseComponent</code>; otherwise, the <code>right</code> higher-order component is applied. If the <code>right</code> is not supplied, it will by default render the wrapped component.</p>
<p>There’s plenty of information here to get you on your way. If you’re learning React and want to get your head around HOCs (higher order components), then implementing this library might be a gratifying challenge to take on.</p>
<h4 id="heading-reviewing-the-source-code"><strong>Reviewing the source code</strong></h4>
<p>Up until recently, I wouldn’t take much time to see how the packages I use most frequently work under the hood. Being without Google or StackOverflow made me desperate and so I started to look inside. I don’t know what I expected to see, but it wasn’t a minified, garbled mess.</p>
<p>Opening Pandora’s box didn’t send a swarm of scorn, hate and famine to taunt me and my family. Instead I was welcomed with cleanly written and well-documented code.</p>
<p>You can even take a peek to see how the people at Lodash write their solutions differently to yours:</p>
<pre><code class="lang-js">
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">concat</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">var</span> length = <span class="hljs-built_in">arguments</span>.length;
  <span class="hljs-keyword">if</span> (!length) {
    <span class="hljs-keyword">return</span> [];
  }
  <span class="hljs-keyword">var</span> args = <span class="hljs-built_in">Array</span>(length - <span class="hljs-number">1</span>),
      array = <span class="hljs-built_in">arguments</span>[<span class="hljs-number">0</span>],
      index = length;

  <span class="hljs-keyword">while</span> (index--) {
    args[index - <span class="hljs-number">1</span>] = <span class="hljs-built_in">arguments</span>[index];
  }
  <span class="hljs-keyword">return</span> arrayPush(isArray(array) ? copyArray(array) : [array], baseFlatten(args, <span class="hljs-number">1</span>));
}
</code></pre>
<p>You’ll learn new ways of achieving the same goals. Maybe their solutions are more efficient, maybe yours are. It’s still a great way to open your eyes to new paradigms and patterns.</p>
<h4 id="heading-developing-your-own-utility-functions"><strong>Developing your own utility functions</strong></h4>
<p>Lodash gets a bad rep as a library that has a large footprint. Projects may need a small number of the utilities. We will still import the whole library as a dependency.</p>
<p>You could download the couple of functions that you use. Why not use the methods you spent 8 hours writing whilst flying over the Pacific Ocean? It might not be quite as robust. But you’ll always be reminded of your journey to Angular Fest Hawaii ’19 whenever you whip out your implementation of <code>_.memoize</code>.</p>
<h4 id="heading-keep-things-simple"><strong>Keep things simple</strong></h4>
<p>Traveling’s draining and flying’s stressful. When feeling fatigued, any level of bureaucracy that sits in the way of any programming becomes a barrier. The idea is to choose a task that gets you coding with as little friction as possible.</p>
<p>I didn’t want to faff around with a bunch of random dependencies and messy vendor code when packed between two snorers on my overnight flight to Canada. It was a happy accident discovering that Lodash doesn’t rely on any external modules. The Lodash package itself is laid out simply. Each method has its own file, which may import a couple of base or utility methods.</p>
<h4 id="heading-becoming-familiar-with-your-tools-of-choice"><strong>Becoming familiar with your tools of choice</strong></h4>
<p>If you’re reading this article, chances are you’re familiar with JavaScript. Like most other modern programming languages, JavaScript receives semi-regular updates. These updates give you access to some new features. Implementing a library might take you to corners of your chosen language that you’ve never been before. It happened to me.</p>
<p>In fact, I recently came across some of JavaScript’s newer <a target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects#Keyed_collections">built-in objects</a>. I’d never used them in code before, so I made a conscious effort to integrate some of them into the utility methods I made:</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> difference = <span class="hljs-function">(<span class="hljs-params">arr, ...otherArgs</span>) =&gt;</span> {
  <span class="hljs-keyword">if</span> (!isValidArray(arr)) <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">TypeError</span>(<span class="hljs-string">'First argument must be an array'</span>);

  <span class="hljs-keyword">const</span> combinedArguments = otherArgs.reduce(<span class="hljs-function">(<span class="hljs-params">acc, item</span>) =&gt;</span> [...acc, ...item], [])
  <span class="hljs-keyword">if</span> (!isValidArray(combinedArguments)) <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">TypeError</span>(<span class="hljs-string">'2nd to nth arguments must be arrays'</span>);

  <span class="hljs-keyword">const</span> differenceSet = <span class="hljs-keyword">new</span> <span class="hljs-built_in">Set</span>([...arr]);
  combinedArguments.forEach(<span class="hljs-function"><span class="hljs-params">item</span> =&gt;</span> {
    <span class="hljs-keyword">if</span> (differenceSet.has(item)) differenceSet.delete(item);
  });

  <span class="hljs-keyword">return</span> [...differenceSet]
}
</code></pre>
<p>Using <code>Set()</code> makes a lot of sense here. What separates it from a normal array is that only unique values can be stored. This means you can’t have any duplicate values inside of your set. This works well when trying to create a function that removes duplicate values.</p>
<p>Whether you’re a guitarist, a painter, or a molecular physicist, you’re not going to get far without familiarizing yourself with your guitar, or your paints, or your … molecules?</p>
<p>The same goes with being a programmer. Master your tools and actively seek gaps in your knowledge. Make a conscious effort to implement features that you haven’t come across before. Or use ones that you find intimidating. It’s one of the strongest ways to learn.</p>
<h3 id="heading-conclusion"><strong>Conclusion</strong></h3>
<p>This isn’t the only way to stay productive when without internet, but it’s worked well for me. In fact, it’s something I recommend people do in the early stages of their programming careers.</p>
<p>I’d love to know if you’ve done something similar, or if you have your own ways of staying sharp without the internet. Let me know below!</p>
<p>Do you know any other packages that would lend themselves well to being rewritten?</p>
<h4 id="heading-thanks-for-reading">Thanks for reading!</h4>
<p>Knowledge sharing is one of the cornerstones of what makes the development community so great. Please don’t hesitate to comment your solutions.</p>
<p>If you’re interested in hosting me at a conference, meetup, or as a speaking guest for any engagement, then you can DM me on <a target="_blank" href="https://twitter.com/andricokaroulla?lang=en">twitter</a>!</p>
<p>I hope this article taught you something new. I post regularly, so if you want to keep up to date with my latest releases then you can follow me. And remember, the longer you hold the clap button, the more claps you can give. ???</p>
<h4 id="heading-you-can-also-check-out-my-other-articles-below">You can also check out my other articles below:</h4>
<p><a target="_blank" href="https://codeburst.io/add-a-touch-of-suspense-to-your-web-app-with-react-lazy-374e66ee05af"><em>Add a touch of Suspense to your web app with React.lazy()</em></a></p>
<p><a target="_blank" href="https://medium.com/@andricokaroulla/updated-for-apollo-v2-1-managing-local-state-with-apollo-d1882f2fbb7"><em>How to use Apollo’s brand new Query components to manage local state</em></a></p>
<p><a target="_blank" href="https://codeburst.io/no-need-to-wait-for-the-holidays-start-decorating-now-67b9dabd60d7"><em>No need to wait for the holidays, start Decorating now</em></a></p>
<p><a target="_blank" href="https://itnext.io/managing-local-state-with-apollo-client-3be522258645"><em>Managing local state with Apollo and Higher Order Components</em></a></p>
<p><a target="_blank" href="https://medium.com/@andricokaroulla/the-react-conference-drinking-game-7a996bfbef3"><em>The React Conference drinking game</em></a></p>
<p><a target="_blank" href="https://codeburst.io/develop-and-deploy-your-own-react-monorepo-app-in-under-2-hours-using-lerna-travis-and-now-2b140d647238"><em>Develop and Deploy your own React monorepo app in under 2 hours, using Lerna, Travis and Now</em></a></p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to use Apollo’s brand new Query components to manage local state ]]>
                </title>
                <description>
                    <![CDATA[ Note: This article deals with utilizing Apollo’s brand new Query and Mutation components, instead of the HOCs. For those that have read the original article here, be aware that the two articles are very similar. Introduction One of Web Development’s ... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/updated-for-apollo-v2-1-managing-local-state-with-apollo-d1882f2fbb7/</link>
                <guid isPermaLink="false">66bb8e01bec1b237336e9683</guid>
                
                    <category>
                        <![CDATA[ Apollo GraphQL ]]>
                    </category>
                
                    <category>
                        <![CDATA[ JavaScript ]]>
                    </category>
                
                    <category>
                        <![CDATA[ General Programming ]]>
                    </category>
                
                    <category>
                        <![CDATA[ React ]]>
                    </category>
                
                    <category>
                        <![CDATA[ technology ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Andrico Karoulla ]]>
                </dc:creator>
                <pubDate>Mon, 04 Jun 2018 07:52:49 +0000</pubDate>
                <media:content url="https://cdn-media-1.freecodecamp.org/images/1*CMxI-q0DAMtcF-VGs10G0Q.jpeg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Note: This article deals with utilizing Apollo’s brand new Query and Mutation components, instead of the HOCs. For those that have read the original article <a target="_blank" href="https://itnext.io/managing-local-state-with-apollo-client-3be522258645">here</a>, be aware that the two articles are very similar.</p>
<h3 id="heading-introduction">Introduction</h3>
<p>One of Web Development’s biggest strengths — and weaknesses — is its approach to modularity. A key programming mantra is to choose something (a function, a package) to do a single job and to do it well. The downside to this approach is that a single project can involve juggling dozens of separate technologies and concepts, each focusing on something specific.</p>
<p>So choosing Apollo Client to handle my local state as well as my remote data seems like a no brainer. Why deal with Redux’s boilerplate and idioms when I’ve already got Apollo/GraphQL set up to get data from my backend?</p>
<p>While this article is going to deal with setting up Apollo to handle local state, it’s not going to be an introduction to the tech. (This legit <a target="_blank" href="https://www.howtographql.com/">howtographql</a> tutorial is a good start for that).</p>
<p>Note: The finished repo can be found <a target="_blank" href="https://github.com/andrico1234/apollo-local-state-starter">here</a>. You can pore through the code if you get stuck or feel confused.</p>
<h3 id="heading-getting-set-up">Getting set up</h3>
<p>We’ll start by cloning the corresponding repo from <a target="_blank" href="https://github.com/andrico1234/apollo-state-blog-repo">here</a>. This repo contains a simple react website, with a sidebar, header, and a body. It’s pretty static in nature, no dynamic content (…yet). By the end of this tutorial, we’ll have Apollo managing the state of the website. Clicking an item in the sidebar will change the state of the website, which in turn updates the header to display the new data.</p>
<p>If you check <code>package.json</code> you’ll see that we’ve only got the basics, plus some additional packages pertaining to our parcel setup.</p>
<p>After cloning the repo, run your standard commands in your command line interface.</p>
<pre><code>&gt; yarn
&gt; yarn dev
</code></pre><p>To install all of your packages and to whip up a local server, go to localhost:1234 and you’ll hopefully see the demo website in all of its glory. It’s static right now, so clicking around won’t do a thing.</p>
<p>What we want to do first and foremost is to get Apollo in our project, so install these packages. <code>apollo-client</code> lets us configure our instance of Apollo, and <code>react-apollo</code> is the driver that allows us to integrate it into our React application. Due to an issue with parcel (I think) we’ll also need to install <code>graphql</code>.</p>
<pre><code>&gt; yarn add apollo-client react-apollo graphql
</code></pre><p>Create a new directory <code>src/apollo</code>, crack open an <code>index.js</code> file, and add the following:</p>
<pre><code class="lang-js"><span class="hljs-keyword">import</span> ApolloClient <span class="hljs-keyword">from</span> ‘apollo-client’;
<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> client = <span class="hljs-keyword">new</span> ApolloClient({});
</code></pre>
<p>This initializes our Apollo Client, which we will then use to wrap our React application by adding the following inside of our <code>src/index.js</code> file.</p>
<pre><code class="lang-js"><span class="hljs-keyword">import</span> { ApolloProvider } <span class="hljs-keyword">from</span> ‘react-apollo’;
<span class="hljs-keyword">import</span> { client } <span class="hljs-keyword">from</span> ‘./apollo’;

<span class="hljs-keyword">const</span> WrappedApp = (
  <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">ApolloProvider</span> <span class="hljs-attr">client</span>=<span class="hljs-string">{client}</span> &gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">App</span> /&gt;</span>
  <span class="hljs-tag">&lt;/<span class="hljs-name">ApolloProvider</span>&gt;</span></span>
);

ReactDOM.render(WrappedApp, <span class="hljs-built_in">document</span>.getElementById(‘root’));
<span class="hljs-comment">// Don’t be a sap. Wrap your app.</span>
</code></pre>
<p>We now have Apollo ready to use in our app. Everything builds when we restart our dev server, but we get an error when we try and access it in the browser. The console will tell us that we need to specify the link and cache properties for our Apollo client, so let’s do that.</p>
<pre><code>&gt; yarn add apollo-link apollo-cache-inmemory apollo-link-state
</code></pre><p>The previous line adds the new Apollo dependencies to our application while the following code resolves the console errors we were getting. So go back to <code>apollo/index.js</code> and update it so the file looks like this:</p>
<pre><code class="lang-js"><span class="hljs-keyword">import</span> ApolloClient <span class="hljs-keyword">from</span> ‘apollo-client’;
<span class="hljs-keyword">import</span> { InMemoryCache } <span class="hljs-keyword">from</span> ‘apollo-cache-inmemory’;
<span class="hljs-keyword">import</span> { ApolloLink } <span class="hljs-keyword">from</span> ‘apollo-link’;
<span class="hljs-keyword">import</span> { withClientState } <span class="hljs-keyword">from</span> ‘apollo-link-state’;

<span class="hljs-keyword">const</span> cache = <span class="hljs-keyword">new</span> InMemoryCache();
<span class="hljs-keyword">const</span> stateLink = withClientState({
  cache
});

<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> client = <span class="hljs-keyword">new</span> ApolloClient({
  cache,
  <span class="hljs-attr">link</span>: ApolloLink.from([
    stateLink,
  ]),
})
</code></pre>
<p>Let’s create an instance of our cache. The cache is Apollo’s normalized data store that stores the results of the query in a flattened data structure. We will read from the cache when we make our GraphQL query, and we’ll write to the cache when we make our mutation resolver.</p>
<p>You can see we’ve also added <code>link</code> to our client object. The <code>ApolloLink.from()</code>method lets us modularly configure how our queries are sent over HTTP. We can use this to handle errors and authorization, and to provide access to our backend. We’re not going to be doing any of this in the tutorial, but we will set up our client state here. So we create <code>const stateLink</code> above and pass in our cache. We’ll add our default state and resolvers here later.</p>
<p>Going back to the browser, you’ll see our lovely static site displaying in all of its magnificence. Let’s add some default state to our project and fire off our first query.</p>
<p>Inside of the Apollo directory, create a new directory called <code>defaults</code> and add an <code>index.js</code> inside of it. The file will contain the following:</p>
<pre><code class="lang-js"><span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> {
  <span class="hljs-attr">apolloClientDemo</span>: {
    <span class="hljs-attr">__typename</span>: ‘ApolloClientDemo’,
    <span class="hljs-attr">currentPageName</span>: ‘Apollo Demo’,
  }
}
</code></pre>
<p>We create an object which acts as the default state of our site. apolloClientDemo is the name of the data structure we want to access when we make our queries. The <code>__typename</code> is the mandatory identifier that our cache uses, and the currentPageName is the specific item of data that our header will use to — you guessed it — display the current page name.</p>
<p>We’ll need to add this to our <code>apollo/index.js</code> file:</p>
<pre><code class="lang-js"><span class="hljs-keyword">import</span> defaults <span class="hljs-keyword">from</span> ‘./defaults’;

<span class="hljs-keyword">const</span> stateLink = withClientState({
  cache,
  defaults,
});
</code></pre>
<p>Let’s clear this up a little bit. <code>import</code> and <code>default</code> are both keywords associated with importing modules, but coincidentally the name of the object we’re exporting from <code>./defaults</code> is also called <code>defaults</code> (so don’t be thinking that I’m using <code>import/export</code> wrong). Treat this import line as if it was just any regular ol’ named import.</p>
<p>With that out of the way, let’s go make a query!</p>
<h3 id="heading-how-to-make-a-query">How to make a query</h3>
<p>Add the following package to your project:</p>
<pre><code>&gt; yarn add graphql-tag
</code></pre><p>and create a new directory <code>src/graphql</code>. In there, create two new files: <code>index.js</code> and <code>getPageName.js</code>. The GraphQL directory will house all the queries and mutations. We’ll create our query in <code>getPageName.js</code> by writing the following:</p>
<pre><code class="lang-js"><span class="hljs-keyword">import</span> gql <span class="hljs-keyword">from</span> ‘graphql-tag’;

<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> getPageNameQuery = gql<span class="hljs-string">`
  query {
    apolloClientDemo @client {
      currentPageName
    }
  }
`</span>;

<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> getPageNameOptions = ({
  <span class="hljs-attr">props</span>: <span class="hljs-function">(<span class="hljs-params">{ data: { apolloClientDemo } }</span>) =&gt;</span> ({
    apolloClientDemo
  })
});
</code></pre>
<p>So we’re exporting two variables, the query and the options. If you’ve used GraphQL before, then the query will look familiar. We’re querying against the apolloClientDemo data structure, retrieving back nothing more than the currentPageName. You’ll notice that we’ve added the <code>@client</code> directive to our query. This tells Apollo to query our local state instead of sending the request to the backend.</p>
<p>Below you’ll see that we’re exporting some options. This is simply defining how we want the data to look when we map the results to the props. We’re destructuring the GraphQL response and sending it to our view so it looks like this:</p>
<pre><code class="lang-js">props: {
  <span class="hljs-attr">currentPageName</span>: ‘Apollo Demo’,
}
<span class="hljs-comment">// and not this</span>
<span class="hljs-attr">props</span>: {
  <span class="hljs-attr">data</span>: {
    <span class="hljs-attr">apolloClientDemo</span>: {
      <span class="hljs-attr">currentPageName</span>: ‘Apollo Demo’,
    }
  }
}
</code></pre>
<p>Go to the <code>graphql/index.js</code> file and export the query as follows:</p>
<pre><code class="lang-js"><span class="hljs-keyword">export</span> { getPageNameQuery, getPageNameOptions } <span class="hljs-keyword">from</span> ‘./getPageName’;
</code></pre>
<p>Again, while this isn’t completely necessary for a small demo/project, this file is handy should your application grow larger. Having your queries exported from a single centralized location keeps everything organized and scalable.</p>
<p>Add to your Header.js:</p>
<pre><code class="lang-js"><span class="hljs-keyword">import</span> React <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>;
<span class="hljs-keyword">import</span> { Query } <span class="hljs-keyword">from</span> <span class="hljs-string">'react-apollo'</span>;
<span class="hljs-keyword">import</span> { getPageNameQuery } <span class="hljs-keyword">from</span> <span class="hljs-string">'../graphql'</span>;

<span class="hljs-keyword">const</span> Header = <span class="hljs-function">() =&gt;</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">Query</span> <span class="hljs-attr">query</span>=<span class="hljs-string">{getPageNameQuery}</span>&gt;</span>
        {({ loading, error, data }) =&gt; {
            if (error) return <span class="hljs-tag">&lt;<span class="hljs-name">h1</span>&gt;</span>Error...<span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>;
            if (loading || !data) return <span class="hljs-tag">&lt;<span class="hljs-name">h1</span>&gt;</span>Loading...<span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>;

            return <span class="hljs-tag">&lt;<span class="hljs-name">h1</span>&gt;</span>{data.apolloClientDemo.currentPageName}<span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>
        }}
    <span class="hljs-tag">&lt;/<span class="hljs-name">Query</span>&gt;</span></span>
);

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> Header;
</code></pre>
<p>This is our first use of Apollo’s new Query Component, which was added in 2.1. We import <code>Query</code> from <code>react-apollo</code> and use it to wrap the rest of our component. We then pass the getPageNameQuery as a value in the query prop. When our component renders, it fires off the query and gives the rest of the component access to the data, which we destructure to gain access to loading, errors, and data.</p>
<p>The Query Component uses the render props pattern to give the rest of our component access to the information returned from the query. If you’ve used the React Context API in 16.3, then you’ve seen this syntax before. Otherwise it’s worth checking out the official React docs <a target="_blank" href="https://reactjs.org/docs/render-props.html">here</a>, as the Render Props pattern is becoming increasingly popular.</p>
<p>In our component, we do a few checks to see if there were any errors when firing the query or if we’re still waiting for data to be returned. If either of these scenarios are true, we return the corresponding HTML. If the query was fired correctly, the component will dynamically display the title of the current page. As we haven’t added our mutation yet, it will only display the default value. But you can change whatever’s in the default state and the website will reflect that.</p>
<p>Now all that’s left to do is mutate the data in the Apollo cache by clicking on the sidebar item.</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/0*OHpQBcsRCsX5Wk_b." alt="Image" width="800" height="600" loading="lazy">
_A refreshing image to break up the text. [Jeff Sheldon](https://unsplash.com/@ugmonk?utm_source=medium&amp;utm_medium=referral" rel="noopener" target="<em>blank" title=")</em></p>
<h3 id="heading-mutations">Mutations</h3>
<p>Things get a little more complicated when dealing with mutations. We no longer just retrieve data from the Apollo store, but we update it too. The architecture of mutation is as follows:</p>
<p><strong>&gt; U</strong>ser clicks sidebar item</p>
<p><strong>&gt; Se</strong>nds variable to mutation</p>
<p><strong>&gt; Fi</strong>res mutation with variable</p>
<p><strong>&gt; G</strong>ets sent to the instance of Apollo</p>
<p><strong>&gt; Fi</strong>nds corresponding resolver</p>
<p><strong>&gt; Appl</strong>ies logic to the Apollo store</p>
<p><strong>&gt; Se</strong>nds data back to header</p>
<p>If that’s difficult to remember, then use this handy mnemonic created using a mnemonic generator: Urban Senile Fauns Groped Faithless Aslan Solemnly. (easy…)</p>
<p>Start by creating a file <code>graphql/updatePageName.js</code>.</p>
<pre><code class="lang-js"><span class="hljs-keyword">import</span> gql <span class="hljs-keyword">from</span> ‘graphql-tag’;

<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> updatePageName = gql<span class="hljs-string">`
  mutation updatePageName($name: String!) {
    updatePageName(name: $name) @client {
      currentPageName
    }
  }
`</span>;
</code></pre>
<p>and export it just like we did with the query.</p>
<pre><code class="lang-js"><span class="hljs-keyword">export</span> { updatePageNameMutation } <span class="hljs-keyword">from</span> ‘./updatePageName’;
</code></pre>
<p>You’ll notice a few differences regarding the mutation. First off we’ve changed the keyword from query to mutation. This lets GraphQL know the type of action we’re performing. We’re also defining the name of the query and adding types to the variables we’re passing in. Inside here we’re specifying the name of the resolver we’ll be using to carry out the changes. We’re also passing through the variable and adding the <code>@client</code> directive.</p>
<p>Unlike the query, we can’t just add the mutation to our view and expect anything to happen. We’ll have to go back to our Apollo directory and add our resolvers. So go ahead and create a new directory <code>apollo/resolvers</code>, and files <code>index.js</code> and <code>updatePageName.js</code>. Inside of <code>updatePageName.js</code>add the following:</p>
<pre><code class="lang-js"><span class="hljs-keyword">import</span> gql <span class="hljs-keyword">from</span> ‘graphql-tag’;

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> (_, { name }, { cache }) =&gt; {
  <span class="hljs-keyword">const</span> query = gql<span class="hljs-string">`
    query GetPageName {
      apolloClientDemo @client {
        currentPageName
      }
    }
  `</span>;

  <span class="hljs-keyword">const</span> previousState = cache.readQuery({ query });

  <span class="hljs-keyword">const</span> data = {
    <span class="hljs-attr">apolloClientDemo</span>: {
      …previousState.apolloClientDemo,
      <span class="hljs-attr">currentPageName</span>: name,
    },
  };

  cache.writeQuery({
    query,
    data,
  });

  <span class="hljs-keyword">return</span> <span class="hljs-literal">null</span>;
};
</code></pre>
<p>There are a lot of interesting things going on in this file. Fortunately, it’s all very logical and doesn’t add many new concepts to what we’ve seen before.</p>
<p>So by default, when a resolver gets called, Apollo passes in all of the variables and the cache. The first argument is a simple ‘_’ because we don’t need to use it. The second argument is the variables object, and the final argument is the cache.</p>
<p>Before we can make changes to the Apollo store, we’ll need to retrieve it. So we make a simple request to get the current content from the store and assign it to previousState. Inside of the data variable, we create a new object with the new information we want to add to the store, which we then write to. You can see that we’ve spread the previous state inside of this object. This is so that only the data we explicitly want to change gets updated. Everything else remains as it is. This prevents Apollo from needlessly updating components whose data hasn’t changed.</p>
<p>Note: while this isn’t completely necessary for this example, it’s super useful when queries and mutations handle larger amounts of data, so I’ve kept it in for the sake of scalability.</p>
<p>Meanwhile in the <code>resolvers/index.js</code> file…</p>
<pre><code class="lang-js"><span class="hljs-keyword">import</span> updatePageName <span class="hljs-keyword">from</span> ‘updatePageName’;

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> {
  <span class="hljs-attr">Mutation</span>: {
    updatePageName,
  }
};
</code></pre>
<p>This is the shape of object that Apollo expects when we pass in our resolvers in to stateLink back in <code>apollo/index.js</code>:</p>
<pre><code class="lang-js"><span class="hljs-keyword">import</span> resolvers <span class="hljs-keyword">from</span> ‘./resolvers’;

<span class="hljs-keyword">const</span> stateLink <span class="hljs-keyword">from</span> = withClientState({
  cache,
  defaults,
  resolvers,
});
</code></pre>
<p>All that’s left to do is add the mutation to our sidebar component.</p>
<pre><code class="lang-js"><span class="hljs-comment">// previous imports</span>
<span class="hljs-keyword">import</span> { Mutation } <span class="hljs-keyword">from</span> ‘react-apollo’;
<span class="hljs-keyword">import</span> { updatePageNameMutation } <span class="hljs-keyword">from</span> ‘../graphql’;

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Sidebar</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">React</span>.<span class="hljs-title">Component</span> </span>{
  render() {
    <span class="hljs-keyword">return</span> (
      <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">Mutation</span> <span class="hljs-attr">mutation</span>=<span class="hljs-string">{updatePageNameMutation}</span>&gt;</span>
        {updatePageName =&gt; (
          // outer div elements
          <span class="hljs-tag">&lt;<span class="hljs-name">li</span> <span class="hljs-attr">className</span>=<span class="hljs-string">“sidebar-item”</span> <span class="hljs-attr">onClick</span>=<span class="hljs-string">{()</span> =&gt;</span> updatePageName({ variables: { name: ‘React’} })}&gt;React<span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
          // other list items and outer div elements
        )}
      <span class="hljs-tag">&lt;/<span class="hljs-name">Mutation</span>&gt;</span></span>
    );
  }
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> Sidebar;
</code></pre>
<p>Like our resolver file, there’s a lot going on in this file — but it’s new. We import our <code>Mutation</code> component from <code>react-apollo</code>, wrap it around our component, and pass the <code>updatePageNameMutation</code> inside of the <code>mutation</code> prop.</p>
<p>The component now has access to the <code>updatePageName</code> method which fires the mutation whenever it’s called. We do this by adding the method as a handler to the <code>&lt;</code>li&gt;’s onClick property. The method expects to receive on object containing the variables as a parameter, so pass in the name you want to update the header to. If everything works, you should be able to run your dev server and click the sidebar items, which should then change our header.</p>
<h3 id="heading-wrapping-up">Wrapping up</h3>
<p>Hooray! Hopefully everything worked out. If you got stuck, then check out the repo <a target="_blank" href="https://github.com/andrico1234/apollo-local-state-starter">here</a>. It contains all of the finished code. If you’re thinking of using local state management in your next React app, then you can fork this repo and continue from there. If you’re interested in having this article/topic spoken about at a meetup or conference, then send a message my way!</p>
<p>There’s a lot more I wanted to cover in this tutorial, such as async resolvers (think Redux thunk), type checking/creating a schema, and a mutation update. So who knows… maybe I’ll drop another article sometime soon.</p>
<p>I really hope that this tutorial was useful for you. I’d like to shout out <a target="_blank" href="https://www.youtube.com/watch?v=2RvRcnD8wHY">Sara Vieira’s youtube tutorial too</a>, as it helped me get my head around Apollo Client. If I haven’t done my job well enough by leaving you scratching your head, then follow the link. And finally, feel free to hit me up on social media, I’m a big music and tech fan so talk geek to me.</p>
<h4 id="heading-thanks-for-reading">Thanks for reading!</h4>
<p>If you’re interested in hosting me at a conference, meetup or as a speaking guest for any engagement then you can DM me on <a target="_blank" href="https://twitter.com/andricokaroulla?lang=en">twitter</a>!</p>
<h4 id="heading-you-can-check-out-my-other-articles-below">You can check out my other articles below:</h4>
<p><a target="_blank" href="https://medium.com/@andricokaroulla/updated-for-apollo-v2-1-managing-local-state-with-apollo-d1882f2fbb7"><em>How to use Apollo’s brand new Query components to manage local state</em></a></p>
<p>[<em>Add a touch of Suspense to your web app with React.lazy()</em>](http://Add a touch of Suspense to your web app with React.lazy())</p>
<p><a target="_blank" href="https://codeburst.io/no-need-to-wait-for-the-holidays-start-decorating-now-67b9dabd60d7"><em>No need to wait for the holidays, start Decorating now</em></a></p>
<p><a target="_blank" href="https://itnext.io/managing-local-state-with-apollo-client-3be522258645"><em>Managing local state with Apollo and Higher Order Components</em></a></p>
<p><a target="_blank" href="https://medium.com/@andricokaroulla/the-react-conference-drinking-game-7a996bfbef3"><em>The React Conference drinking game</em></a></p>
<p><a target="_blank" href="https://codeburst.io/develop-and-deploy-your-own-react-monorepo-app-in-under-2-hours-using-lerna-travis-and-now-2b140d647238"><em>Develop and Deploy your own React monorepo app in under 2 hours, using Lerna, Travis and Now</em></a></p>
 ]]>
                </content:encoded>
            </item>
        
    </channel>
</rss>
