<?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[ Joe Attardi - 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[ Joe Attardi - freeCodeCamp.org ]]>
            </title>
            <link>https://www.freecodecamp.org/news/</link>
        </image>
        <generator>Eleventy</generator>
        <lastBuildDate>Fri, 08 May 2026 22:31:37 +0000</lastBuildDate>
        <atom:link href="https://www.freecodecamp.org/news/author/joeattardi/rss.xml" rel="self" type="application/rss+xml" />
        <ttl>60</ttl>
        
            <item>
                <title>
                    <![CDATA[ How to Programmatically Highlight Text with the CSS Custom Highlight API ]]>
                </title>
                <description>
                    <![CDATA[ You can highlight text in the browser by clicking and dragging through the desired text. And sometimes this works fine. But there are times when you’ll want to programmatically highlight some text in an HTML document. In this article, I’ll discuss a ... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-programmatically-highlight-text-with-the-css-custom-highlight-api/</link>
                <guid isPermaLink="false">6787d62041c11049156708c3</guid>
                
                    <category>
                        <![CDATA[ JavaScript ]]>
                    </category>
                
                    <category>
                        <![CDATA[ CSS ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Web Development ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Joe Attardi ]]>
                </dc:creator>
                <pubDate>Wed, 15 Jan 2025 15:37:04 +0000</pubDate>
                <media:content url="https://cdn.hashnode.com/res/hashnode/image/upload/v1736955360118/bd658ef5-734c-4e21-ad0e-be2dac0b7eee.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>You can highlight text in the browser by clicking and dragging through the desired text. And sometimes this works fine. But there are times when you’ll want to programmatically highlight some text in an HTML document.</p>
<p>In this article, I’ll discuss a couple ways you can do this. The first is using the &lt;mark&gt; element, and the second is using the CSS Custom Highlight API. We’ll go through examples, and I’ll explain the issues with <code>&lt;mark&gt;</code>. Then you’ll learn how the Custom Highlight API solves these challenges.</p>
<h3 id="heading-heres-what-well-cover">Here’s what we’ll cover:</h3>
<ol>
<li><p><a class="post-section-overview" href="#heading-what-we-want-to-do">What We Want to Do</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-reasons-for-highlighting-text">Reasons for Highlighting Text</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-highlight-text-using-the-element">How to Highlight Text Using the Mark Element</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-introducing-the-css-custom-highlight-api">Introducing the CSS Custom Highlight API</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-apply-a-custom-highlight">How to Apply a Custom Highlight</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-modify-a-highlighted-range">How to Modify a Highlighted Range</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-highlight-multiple-ranges">How to Highlight Multiple Ranges</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-remove-highlights">How to Remove Highlights</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-browser-support">Browser Support</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-wrapping-up">Wrapping Up</a></p>
</li>
</ol>
<h2 id="heading-what-we-want-to-do">What We Want to Do</h2>
<p>We want to apply highlighting effects to some text in a document, without needing to manually select the text. Typically, we’d do this by giving the text a background color that calls attention to the highlighted text. You can see what this looks like in the following screenshot.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1736729603375/cb0e081b-a848-4079-8b8e-67815d56711d.png" alt="Demonstration of highlighted text" class="image--center mx-auto" width="600" height="400" loading="lazy"></p>
<h2 id="heading-reasons-for-highlighting-text">Reasons for Highlighting Text</h2>
<p>There are several use cases for programmatically highlighting text. Before we talk about <em>how</em> to highlight, let's talk about <em>why</em> we might want to highlight.</p>
<ul>
<li><p><strong>Highlighting search results or matches</strong>: If the user reaches this page by searching, it may help them to call out the matching search text by applying highlighting.</p>
</li>
<li><p><strong>Emphasizing information</strong>: We might want to call out some important text on the page.</p>
</li>
<li><p><strong>User defined highlighting</strong>: An example would be in an e-reading app like Amazon's Kindle app. Here, users can select and save highlighted regions of a book. Later, when returning to a page, the user's previous highlights are shown.</p>
</li>
</ul>
<h2 id="heading-how-to-highlight-text-using-the-element">How to Highlight Text Using the <code>&lt;mark&gt;</code> Element</h2>
<p>One way you can highlight text is by using the <a target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/HTML/Element/mark">HTML <code>&lt;mark&gt;</code> element</a>. This has the benefit of being an HTML semantic element.</p>
<p>To highlight text using <code>&lt;mark&gt;</code>, you can wrap the text to highlight in a <code>&lt;mark&gt;</code> element. The browser will apply a highlight style to any text inside a <code>&lt;mark&gt;</code> element.</p>
<p>Consider the following HTML containing a <code>&lt;mark&gt;</code> element which surrounds the text you want to highlight.</p>
<pre><code class="lang-html">Here is some <span class="hljs-tag">&lt;<span class="hljs-name">mark</span>&gt;</span>text to highlight<span class="hljs-tag">&lt;/<span class="hljs-name">mark</span>&gt;</span>.
</code></pre>
<p><code>&lt;mark&gt;</code> can be styled with CSS like any other HTML element, so you can customize the color and style of the highlighted text.</p>
<p>Using the <code>&lt;mark&gt;</code> element has some drawbacks, though. You have to modify the DOM and insert nodes whenever you want to add highlighting. This can cause side effects such as a layout recalculation that can affect the page's performance.</p>
<p>It's also harder to highlight text that might span multiple HTML elements. Since <code>&lt;mark&gt;</code> is an HTML element, you have to use it in such a way that it produces valid HTML.</p>
<p>For the rest of this article, we'll use some example HTML markup that we want to highlight parts of. Consider this HTML markup containing an introductory paragraph and some list items. We want to apply highlighting to some of the content, but let's show the base HTML first.</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>Some introductory text.<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>

<span class="hljs-tag">&lt;<span class="hljs-name">ul</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">li</span>&gt;</span>Item one<span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">li</span>&gt;</span>Item two<span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">ul</span>&gt;</span>
</code></pre>
<p>Now, suppose we want to highlight "Some introductory text." <em>and</em> "Item one" together. We can't use a single <code>&lt;mark&gt;</code> element, because it would be invalid HTML.</p>
<p>The closing tag would be nested inside a <code>&lt;li&gt;</code> element, which is not valid HTML. The following code shows what that might look like:</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span><span class="hljs-tag">&lt;<span class="hljs-name">mark</span>&gt;</span>Some introductory text.<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>

<span class="hljs-tag">&lt;<span class="hljs-name">ul</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">li</span>&gt;</span>Item one<span class="hljs-tag">&lt;/<span class="hljs-name">mark</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">li</span>&gt;</span>Item two<span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">ul</span>&gt;</span>
</code></pre>
<p>Instead, to achieve the desired effect, we would have to insert multiple <code>&lt;mark&gt;</code> elements as shown in the following code. Note that there are two <code>&lt;mark&gt;</code> elements: one in the introduction, and one in the first list item. If you wanted to highlight multiple list items, you'd need to add even more <code>&lt;mark&gt;</code> elements.</p>
<p>Here's some example code with multiple <code>&lt;mark&gt;</code> elements:</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span><span class="hljs-tag">&lt;<span class="hljs-name">mark</span>&gt;</span>Some introductory text.<span class="hljs-tag">&lt;/<span class="hljs-name">mark</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>

<span class="hljs-tag">&lt;<span class="hljs-name">ul</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">li</span>&gt;</span><span class="hljs-tag">&lt;<span class="hljs-name">mark</span>&gt;</span>Item one<span class="hljs-tag">&lt;/<span class="hljs-name">mark</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">li</span>&gt;</span>Item two<span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">ul</span>&gt;</span>
</code></pre>
<p>This works, but it's cumbersome and does not result in a single continuous highlight.</p>
<h2 id="heading-introducing-the-css-custom-highlight-api">Introducing the CSS Custom Highlight API</h2>
<p>The solution to our problem is the <a target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/API/CSS_Custom_Highlight_API">CSS Custom Highlight API</a>, a newer API that lets you create highlight regions and style them with CSS. Highlights are tied to <em>ranges</em>, which can span multiple HTML elements and do not add any markup or elements to the document.</p>
<p>There are several concepts you’ll need to know when using this API:</p>
<ul>
<li><p><a target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/API/Range"><code>Range</code></a>: A <code>Range</code> is an object representing part of a document between two nodes. These can be element nodes or text nodes.</p>
</li>
<li><p><a target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/API/Highlight"><code>Highlight</code></a>: A <code>Highlight</code> is an object that defines a custom highlight around one or more <code>Range</code> objects. These objects are registered with the CSS engine under a unique name.</p>
</li>
<li><p><a target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/API/HighlightRegistry">CSS highlight registry</a>: A global object where <code>Highlight</code> objects are registered under unique names.</p>
</li>
<li><p><a target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/CSS/::highlight">The <code>::highlight</code> pseudo-element</a>: This is used in a CSS stylesheet to define the highlighting style. Each <code>::highlight</code> pseudo-element references a <code>Highlight</code> object name that was registered with the CSS highlight registry.</p>
</li>
</ul>
<h2 id="heading-how-to-apply-a-custom-highlight">How to Apply a Custom Highlight</h2>
<p>Let's return to the earlier highlighting example and use the CSS Custom Highlight API to highlight the introductory text and the first list item.</p>
<p>First, let's add some IDs so we can select the relevant elements more easily. Consider this updated code where we have added IDs to some of the elements.</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">p</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"intro"</span>&gt;</span>Introductory text.<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>

<span class="hljs-tag">&lt;<span class="hljs-name">ul</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">li</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"item1"</span>&gt;</span>Item one<span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">li</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"item2"</span>&gt;</span>Item two<span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">ul</span>&gt;</span>
</code></pre>
<p>Let's walk through the steps to create the highlight.</p>
<h3 id="heading-create-the-range">Create the <code>Range</code></h3>
<p>First, we'll create a <code>Range</code> object that spans the desired elements. This will represent a range of elements that spans the introduction and first list item without having to modify the DOM.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> range = <span class="hljs-keyword">new</span> Range();
range.setStartBefore(<span class="hljs-built_in">document</span>.getElementById(<span class="hljs-string">'intro'</span>));
range.setEndAfter(<span class="hljs-built_in">document</span>.getElementById(<span class="hljs-string">'item1'</span>));
</code></pre>
<p>This <code>Range</code> object will start at the beginning of the <code>&lt;p&gt;</code> element, and will end at the end of the <code>&lt;li&gt;</code> with ID <code>item1</code>.</p>
<h3 id="heading-create-and-register-the-highlight-object">Create and Register the <code>Highlight</code> Object</h3>
<p>Now that we have a <code>Range</code>, we can create a <code>Highlight</code> for that <code>Range</code>. We do this by calling the <a target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/API/Highlight/Highlight"><code>Highlight</code> constructor</a>, passing the <code>Range</code> object as its argument.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> highlight = <span class="hljs-keyword">new</span> Highlight(range);
</code></pre>
<p>This creates the <code>Highlight</code> object, but we can't do anything with it yet. First, we'll need to register it with the CSS highlight registry with the <a target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/API/HighlightRegistry/set"><code>CSS.highlights.set</code> method</a>.</p>
<p>The following code shows how you can use <code>CSS.highlights.set</code> to register a <code>Highlight</code> object under the name <code>my-custom-highlight</code>. We'll reference this name in the CSS when we apply styling in the next step.</p>
<pre><code class="lang-javascript">CSS.highlights.set(<span class="hljs-string">'my-custom-highlight'</span>, highlight);
</code></pre>
<h3 id="heading-style-the-highlight">Style the Highlight</h3>
<p>We've created and registered the <code>Highlight</code> around a given <code>Range</code>, but at this point, we still won't see anything in the document. We need to use a CSS rule to define the highlight style.</p>
<p>To do this, we'll use the <code>::highlight</code> pseudo-element. We pass the name of the custom highlight used in the previous step to this pseudo-element. This allows us to set CSS styles that are applied to the text within the highlighted range.</p>
<pre><code class="lang-css"><span class="hljs-selector-pseudo">::highlight(my-custom-highlight)</span> {
  <span class="hljs-attribute">background-color</span>: yellow;
}
</code></pre>
<p>Now, the introductory text and the first list item will be highlighted in yellow, as shown in this screenshot.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1736729896575/97b15f77-e8fc-449e-8a89-ad5658e13605.png" alt="Screenshot showing the initial highlight state" class="image--center mx-auto" width="600" height="400" loading="lazy"></p>
<h2 id="heading-how-to-modify-a-highlighted-range">How to Modify a Highlighted <code>Range</code></h2>
<p>When we create a <code>Highlight</code> object around a <code>Range</code> object, the <code>Highlight</code> will be dynamically updated with any changes made to the <code>Range</code>. In our example, let's say we now want to extend the highlight to the second list item.</p>
<p>We don't need to create a new <code>Highlight</code> or <code>Range</code> – rather, we can just set the <code>Range</code>'s end position to the new element.</p>
<pre><code class="lang-javascript">range.setEndAfter(<span class="hljs-built_in">document</span>.getElementById(<span class="hljs-string">'item2'</span>));
</code></pre>
<p>As soon as the <code>Range</code> is modified, the new text will be highlighted as shown in this screenshot.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1736729961827/8633c59b-485d-4ba6-a716-7dcb084fddae.png" alt="The second list item is now highlighted" class="image--center mx-auto" width="600" height="400" loading="lazy"></p>
<h2 id="heading-how-to-highlight-multiple-ranges">How to Highlight Multiple <code>Range</code>s</h2>
<p>For even more flexibility, a single <code>Highlight</code> can cover multiple <code>Range</code>s. Let's update our example HTML to include four list items.</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">p</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"intro"</span>&gt;</span>Introductory text.<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>

<span class="hljs-tag">&lt;<span class="hljs-name">ul</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">li</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"item1"</span>&gt;</span>Item one<span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">li</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"item2"</span>&gt;</span>Item two<span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">li</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"item3"</span>&gt;</span>Item three<span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">li</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"item4"</span>&gt;</span>Item four<span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">ul</span>&gt;</span>
</code></pre>
<p>So far, we're highlighting the introductory text and the first two list items. Suppose we now want to also highlight the fourth list item. We can't do this with our existing <code>Range</code> object, since it wouldn't represent a contiguous range of nodes. We'll need to create a second <code>Range</code>. This new <code>Range</code> spans the fourth list item.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> item4 = <span class="hljs-built_in">document</span>.getElementById(<span class="hljs-string">'item4'</span>);
<span class="hljs-keyword">const</span> range2 = <span class="hljs-keyword">new</span> Range();
range2.setStartBefore(item4);
range2.setEndAfter(item4);
</code></pre>
<p>Now, we can add this new <code>Range</code> to our existing <code>Highlight</code> object by calling its <a target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/API/Highlight/add"><code>add</code> method</a>. This will let us apply highlighting to the second <code>Range</code>.</p>
<pre><code class="lang-javascript">highlight.add(range2);
</code></pre>
<p>Once we do this, the fourth list item will be highlighted as well, as shown in this screenshot.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1736730028688/6710e901-6027-46c5-af8e-2d2c3bc7563f.png" alt="The fourth item is now also highlighted" class="image--center mx-auto" width="600" height="400" loading="lazy"></p>
<h2 id="heading-how-to-remove-highlights">How to Remove Highlights</h2>
<p>There are two ways that you can remove highlights from the document.</p>
<p>First, let's suppose we want to remove the highlight from the introductory text and first two list items, but keep the last list item highlighted. We can use the <code>Highlight</code> object's <a target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/API/Highlight/delete"><code>delete</code> method</a> to remove the first <code>Range</code> from the <code>Highlight</code> object.</p>
<pre><code class="lang-javascript">highlight.delete(range);
</code></pre>
<p>After we delete this <code>Range</code>, only the last list item will remain highlighted, as shown in this screenshot.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1736730070050/626121b3-60a3-4491-b9d8-11940d4d34f2.png" alt="Only the last list item is now highlighted" class="image--center mx-auto" width="600" height="400" loading="lazy"></p>
<p>The other way to remove highlights is to un-register a <code>Highlight</code> object from the CSS highlight registry by calling <a target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/API/HighlightRegistry/delete"><code>CSS.highlights.delete</code></a> with the unique name we gave the <code>Highlight</code>. This removes the <code>Highlight</code> object that we registered previously.</p>
<pre><code class="lang-javascript">CSS.highlights.delete(<span class="hljs-string">'my-custom-highlight'</span>);
</code></pre>
<p>Now, nothing will remain highlighted, as shown in this screenshot.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1736730106386/593b7b46-027d-442a-b633-04ac0aecdb4a.png" alt="Nothing is highlighted" class="image--center mx-auto" width="600" height="400" loading="lazy"></p>
<h2 id="heading-browser-support">Browser Support</h2>
<p>As of January 2025, at the time of writing, the CSS Custom Highlight API is supported in Chrome, Edge, and Safari. Firefox support is starting to show up in nightly builds, so you should expect Firefox to have improved support soon. For the latest compatibility data, see <a target="_blank" href="https://caniuse.com/mdn-api_highlight">https://caniuse.com/mdn-api_highlight</a>.</p>
<p>To test if the browser supports CSS custom highlighting, you can check for the existence of the <code>highlights</code> property of the <a target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/API/CSS"><code>CSS</code> object</a>:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">if</span> (!(<span class="hljs-string">'highlights'</span> <span class="hljs-keyword">in</span> CSS)) {
  <span class="hljs-comment">// highlight API is not supported</span>
}
</code></pre>
<h2 id="heading-wrapping-up">Wrapping Up</h2>
<p>The CSS Custom Highlight API lets you programmatically highlight regions of text in an HTML document without having to modify the DOM or worry about inserting invalid HTML markup. Its flexible and dynamic nature lets you add, modify, and remove highlights at runtime.</p>
<h3 id="heading-further-reading">Further Reading</h3>
<ul>
<li><p><a target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/API/Range"><code>Range</code> (MDN)</a>: API documentation for the <code>Range</code> interface.</p>
</li>
<li><p><a target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/API/CSS_Custom_Highlight_API">CSS Custom Highlight API (MDN)</a>: More details about the CSS Custom Highlight API.</p>
</li>
</ul>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How JavaScript Promises Work – Handbook for Beginners ]]>
                </title>
                <description>
                    <![CDATA[ Many operations, such as network requests, are asynchronous in nature. One of the most useful and powerful tools for working with asynchronous code is the Promise. In this handbook, you'll learn all about JavaScript Promises and how to use them. Tabl... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/the-javascript-promises-handbook/</link>
                <guid isPermaLink="false">66ba565c194f72bcfe482c32</guid>
                
                    <category>
                        <![CDATA[ handbook ]]>
                    </category>
                
                    <category>
                        <![CDATA[ JavaScript ]]>
                    </category>
                
                    <category>
                        <![CDATA[ promises ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Joe Attardi ]]>
                </dc:creator>
                <pubDate>Tue, 13 Feb 2024 23:37:58 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2024/02/How-JavaScript-Promises-Work-Cover.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Many operations, such as network requests, are asynchronous in nature. One of the most useful and powerful tools for working with asynchronous code is the Promise. In this handbook, you'll learn all about JavaScript Promises and how to use them.</p>
<h2 id="heading-table-of-contents">Table of Contents</h2>
<ol>
<li><a class="post-section-overview" href="#heading-what-is-a-promise">What is a Promise?</a></li>
<li><a class="post-section-overview" href="#heading-comparing-promises-to-other-async-patterns">Comparing Promises to Other Async Patterns</a></li>
<li><a class="post-section-overview" href="#heading-how-to-create-a-promise">How to Create a Promise</a></li>
<li><a class="post-section-overview" href="#heading-how-to-get-the-result-of-a-promise">How to Get the Result of a Promise</a></li>
<li><a class="post-section-overview" href="#heading-how-to-handle-errors-with-then">How to Handle Errors with <code>then</code></a></li>
<li><a class="post-section-overview" href="#heading-promise-chaining">Promise Chaining</a></li>
<li><a class="post-section-overview" href="#heading-how-to-create-immediately-fulfilled-or-rejected-promises">How to Create Immediately Fulfilled or Rejected Promises</a></li>
<li><a class="post-section-overview" href="#heading-how-to-use-async-and-await">How to Use <code>async</code> and <code>await</code></a></li>
<li><a class="post-section-overview" href="#heading-promise-anti-patterns">Promise Anti-Patterns</a></li>
<li><a class="post-section-overview" href="#heading-summary">Summary</a></li>
</ol>
<h2 id="heading-what-is-a-promise">What is a Promise?</h2>
<p>Let's begin by looking at what a Promise is.</p>
<p>In simple terms, a Promise is an object representing an asynchronous operation. This object can tell you when the operation succeeds, or when it fails. </p>
<p>When you call a Promise-based API, the function returns a Promise object that will eventually provide the result of the operation.</p>
<h3 id="heading-promise-states">Promise states</h3>
<p>During its lifetime, a Promise can be in one of three states:</p>
<ul>
<li><strong>Pending</strong>: A Promise is pending while the operation is still in progress. It's in an idle state, waiting for the eventual result (or error).</li>
<li><strong>Fulfilled</strong>: The asynchronous task that returned the Promise completed successfully. A Promise is fulfilled with a value, which is the result of the operation.</li>
<li><strong>Rejected</strong>: If the asynchronous operation failed, the Promise is said to be rejected. A Promise is rejected with a <em>reason</em>. This typically is an <code>Error</code> object, but a Promise can be rejected with any value – even a simple number or string!</li>
</ul>
<p>A Promise starts out in the pending state, then depending on the result, will transition to either the fulfilled or rejected state. A Promise is said to be <em>settled</em> once it reaches either the fulfilled or rejected state.</p>
<p>Of course, there is no guarantee that the asynchronous task will ever complete. It's completely possible for a <code>Promise</code> to remain in the pending state forever, though this would be because of a bug in the asynchronous task's code.</p>
<h2 id="heading-comparing-promises-to-other-async-patterns">Comparing Promises to Other Async Patterns</h2>
<p>Promises behave a little differently from other asynchronous patterns in JavaScript. Before diving deeper into Promises, let's briefly compare Promises to these other techniques.</p>
<h3 id="heading-callback-functions">Callback functions</h3>
<p>A callback function is a function that you pass to another function. When the function you call has finished its work, it will execute your callback function with the result.</p>
<p>Imagine a function called <code>getUsers</code> which will make a network request to get an array of users. You can pass a callback function to <code>getUsers</code>, which will be called with the array of users once the network request is complete:</p>
<pre><code class="lang-javascript"><span class="hljs-built_in">console</span>.log(<span class="hljs-string">'Preparing to get users'</span>);
getUsers(<span class="hljs-function"><span class="hljs-params">users</span> =&gt;</span> {
  <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'Got users:'</span>, users);
});
<span class="hljs-built_in">console</span>.log(<span class="hljs-string">'Users request sent'</span>);
</code></pre>
<p>First, the above code will print "Preparing to get users". Then it calls <code>getUsers</code> which will initiate the network request. But JavaScript doesn't wait for the request to complete. Instead, it immediately executes the next <code>console.log</code> statement.</p>
<p>Later, once the users have been loaded, your callback will be executed and "Got users" will be printed.</p>
<p>Some callback-based APIs, such as many Node.js APIs, use <em>error-first callbacks</em>. These callback functions take two arguments. The first argument is an error, and the second is the result. </p>
<p>Typically, only one of these will have a value, depending on the outcome of the operation. This is similar to the fulfilled and rejected Promise states.</p>
<p>The trouble with callback APIs is that of nesting. If you need to make multiple asynchronous calls in sequence, you’ll end up with nested function calls and callbacks.</p>
<p>Imagine you want to read a file, process some data from that file, then write a new file. All three of these tasks are asynchronous and use an imaginary callback based API.</p>
<pre><code class="lang-javascript">readFile(<span class="hljs-string">'sourceData.json'</span>, <span class="hljs-function"><span class="hljs-params">data</span> =&gt;</span> {
    processData(data, <span class="hljs-function"><span class="hljs-params">result</span> =&gt;</span> {
        writeFile(result, <span class="hljs-string">'processedData.json'</span>, <span class="hljs-function">() =&gt;</span> {
            <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'Done processing'</span>);
        });
    });
});
</code></pre>
<p>It gets even more unwieldy with error handling. Imagine these functions used error-first callbacks:</p>
<pre><code class="lang-javascript">readFile(<span class="hljs-string">'sourceData.json'</span>, <span class="hljs-function">(<span class="hljs-params">error, data</span>) =&gt;</span> {
    <span class="hljs-keyword">if</span> (error) {
        <span class="hljs-built_in">console</span>.error(<span class="hljs-string">'Error reading file:'</span>, error);
        <span class="hljs-keyword">return</span>;
    }

    processData(data, <span class="hljs-function">(<span class="hljs-params">error, result</span>) =&gt;</span> {
        <span class="hljs-keyword">if</span> (error) {
            <span class="hljs-built_in">console</span>.error(<span class="hljs-string">'Error processing data:'</span>, error);
            <span class="hljs-keyword">return</span>;
        }

        writeFile(result, <span class="hljs-string">'processedData.json'</span>, <span class="hljs-function"><span class="hljs-params">error</span> =&gt;</span> {
            <span class="hljs-keyword">if</span> (error) {
                <span class="hljs-built_in">console</span>.error(<span class="hljs-string">'Error writing file:'</span>, error);
                <span class="hljs-keyword">return</span>;
            }

            <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'Done processing'</span>);
        });
    });
});
</code></pre>
<p>Callback functions aren't typically used directly as an asynchronous mechanism in modern APIs, but as you'll soon see, they are the foundation for other types of asynchronous tools such as Promises.</p>
<h3 id="heading-events">Events</h3>
<p>An event is something that you can listen for and respond to. Some objects in JavaScript are event <em>emitters</em>, which means you can register event listeners on them. </p>
<p>In the DOM, many elements implement the <code>EventTarget</code> interface which provides <code>addEventListener</code> and <code>removeEventListener</code> methods.</p>
<p>A given type of event can occur more than once. For example, you can listen for the click event on a button:</p>
<pre><code class="lang-javascript">myButton.addEventListener(<span class="hljs-string">'click'</span>, <span class="hljs-function">() =&gt;</span> {
   <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'button was clicked!'</span>); 
});
</code></pre>
<p>Every time the button is clicked, the text "button was clicked!" will be printed to the console. </p>
<p><code>addEventListener</code> itself accepts a callback function. Whenever the event occurs, the callback is executed.</p>
<p>An object can emit multiple types of events. Consider an image object. If the image at the specified URL is loaded successfully, the <code>load</code> event is triggered. If there was an error, this event is not triggered and instead the <code>error</code> event is triggered.</p>
<pre><code class="lang-javascript">myImage.addEventListener(<span class="hljs-string">'load'</span>, <span class="hljs-function">() =&gt;</span> {
    <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'Image was loaded'</span>);
});

myImage.addEventListener(<span class="hljs-string">'error'</span>, <span class="hljs-function"><span class="hljs-params">error</span> =&gt;</span> {
   <span class="hljs-built_in">console</span>.error(<span class="hljs-string">'Image failed to load:'</span>, error); 
});
</code></pre>
<p>Suppose the image already completed loading before you added the event listener. What do you think would happen? Nothing! One drawback of event-based APIs is that if you add an event listener after an event, your callback won't be executed. This makes sense, after all – you wouldn't want to receive all past click events when you add a click listener to a button.</p>
<p>Now that we've explored callbacks and events, let's take a closer look at Promises.</p>
<h2 id="heading-how-to-create-a-promise">How to Create a Promise</h2>
<p>You can create a Promise using the <code>new</code> keyword with the <code>Promise</code> constructor. The <code>Promise</code> constructor takes a callback function that takes two arguments, called <code>resolve</code> and <code>reject</code>. Each of these arguments is a function provided by the Promise, which are used to transition the Promise to either the fulfilled or rejected state.</p>
<p>Inside your callback, you perform your asynchronous work. If the task is successful, you call the <code>resolve</code> function with the final result. If there was an error, you call the <code>reject</code> function with the error.</p>
<p>Here's an example of creating a Promise that wraps the browser's <code>setTimeout</code> function:</p>
<pre><code class="lang-javascript"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">wait</span>(<span class="hljs-params">duration</span>) </span>{
    <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">Promise</span>(<span class="hljs-function"><span class="hljs-params">resolve</span> =&gt;</span> {
        <span class="hljs-built_in">setTimeout</span>(resolve, duration);
    });
}
</code></pre>
<p>The <code>resolve</code> function is passed as the first argument to <code>setTimeout</code>. After the time specified by <code>duration</code> has passed, the browser calls the <code>resolve</code> function which fulfills the Promise.</p>
<p>Note: In this example, the delay before the <code>resolve</code> function is called may be longer than the duration passed to the function. This is because <code>setTimeout</code> does not guarantee execution at the specified time.</p>
<p>It's important to note that often times, you won't actually need to construct your own Promise by hand. You will typically be working with Promises returned by other APIs.</p>
<h2 id="heading-how-to-get-the-result-of-a-promise">How to Get the Result of a Promise</h2>
<p>We've seen how to create a Promise, but how do you actually get the result of the asynchronous operation? To do this, you call <code>then</code> on the Promise object itself. <code>then</code> takes a callback function as its argument. When the Promise is fulfilled, the callback is executed with the result.</p>
<p>Let's see an example of this in action. Imagine a function called <code>getUsers</code> that asynchronously loads a list of user objects and returns a Promise. You can get the list of users by calling <code>then</code> on the Promise returned by <code>getUsers</code>.</p>
<pre><code class="lang-javascript">getUsers()
  .then(<span class="hljs-function"><span class="hljs-params">users</span> =&gt;</span> {
    <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'Got users:'</span>, users);
  });
</code></pre>
<p>Just like with events or callback based APIs, your code will continue executing without waiting for the result. Some time later, when the users have been loaded, your callback is scheduled for execution.</p>
<pre><code class="lang-javascript"><span class="hljs-built_in">console</span>.log(<span class="hljs-string">'Loading users'</span>);
getUsers()
  .then(<span class="hljs-function"><span class="hljs-params">users</span> =&gt;</span> {
    <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'Got users:'</span>, users);
  });
<span class="hljs-built_in">console</span>.log(<span class="hljs-string">'Continuing on'</span>);
</code></pre>
<p>In the above example, "Loading users" will be printed first. The next thing that is printed will be "Continuing on", because the <code>getUsers</code> call is still loading the users. Later, you'll see "Got users" printed.</p>
<h2 id="heading-how-to-handle-errors-with-then">How to Handle Errors with <code>then</code></h2>
<p>We've seen how to use <code>then</code> to get the result provided to the Promise, but what about errors? What happens if we fail to load the user list? </p>
<p>The <code>then</code> function actually takes a second argument, another callback. This is the error handler. If the Promise is rejected, this callback is executed with the rejection value.</p>
<pre><code class="lang-javascript">getUsers()
  .then(<span class="hljs-function"><span class="hljs-params">users</span> =&gt;</span> {
    <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'Got users:'</span>, users);
  }, <span class="hljs-function"><span class="hljs-params">error</span> =&gt;</span> {
    <span class="hljs-built_in">console</span>.error(<span class="hljs-string">'Failed to load users:'</span>, error);  
  });
</code></pre>
<p>Since a Promise can only ever be either fulfilled or rejected, but not both, only one of these callback functions will be executed.</p>
<p>It's important to always handle errors when working with Promises. If you have a Promise rejection that isn't handled by an error callback, you'll get an exception in your console about an unhandled rejection, which can cause issues for your users at runtime.</p>
<h2 id="heading-promise-chaining">Promise Chaining</h2>
<p>What if you need to work with multiple Promises in series? Consider the earlier example where we loaded some data from a file, did some processing, and wrote the result to a new file. Suppose the <code>readFile</code>, <code>processData</code>, and <code>writeFile</code> functions used Promises instead of callbacks. </p>
<p>You might try something like this:</p>
<pre><code class="lang-javascript">readFile(<span class="hljs-string">'sourceData.json'</span>)
  .then(<span class="hljs-function"><span class="hljs-params">data</span> =&gt;</span> {
    processData(data)
      .then(<span class="hljs-function"><span class="hljs-params">result</span> =&gt;</span> {
        writeFile(result, <span class="hljs-string">'processedData.json'</span>)
          .then(<span class="hljs-function">() =&gt;</span> {
            <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'Done processing'</span>);
          });
      });
  });
</code></pre>
<p>This doesn't look great, and we still have the nesting issue that we had with the callback approach. Thankfully, there is a better way. You can chain Promises together in a flat sequence.</p>
<p>To see how this works, let's look deeper at how <code>then</code> works. The key idea is this: the <code>then</code> method returns <em>another Promise</em>. Whatever value you return from your <code>then</code> callback becomes the fulfilled value of this new Promise.</p>
<p>Consider a <code>getUsers</code> function that returns a Promise that gets fulfilled with an array of user objects. Suppose we call <code>then</code> on this Promise, and in the callback, return the first user in the array (<code>users[0]</code>):</p>
<pre><code class="lang-javascript">getUsers().then(<span class="hljs-function"><span class="hljs-params">users</span> =&gt;</span> users[<span class="hljs-number">0</span>]);
</code></pre>
<p>This whole expression, then, results in a new Promise that will be fulfilled with the first user object!</p>
<pre><code class="lang-javascript">getUsers()
  .then(<span class="hljs-function"><span class="hljs-params">users</span> =&gt;</span> users[<span class="hljs-number">0</span>])
  .then(<span class="hljs-function"><span class="hljs-params">firstUser</span> =&gt;</span> {
    <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'First user:'</span>, firstUser.username);
  });
</code></pre>
<p>This process of returning a Promise, calling <code>then</code>, and returning another value, resulting in another Promise, is called chaining.</p>
<p>Let's extend this idea. What if, instead of returning a value from the <code>then</code> handler, we returned another Promise? Consider again the file-processing example, where <code>readFile</code> and <code>processData</code> are both asynchronous functions that return Promises:</p>
<pre><code class="lang-javascript">readFile(<span class="hljs-string">'sourceData.json'</span>)
  .then(<span class="hljs-function"><span class="hljs-params">data</span> =&gt;</span> processData(data));
</code></pre>
<p>The <code>then</code> handler calls <code>processData</code>, returning the resulting Promise. As before, this returns a new Promise. In this case, the new Promise will become fulfilled when the Promise returned by <code>processData</code> is fulfilled, giving you the same value. So the code in the above example would return a Promise that will be fulfilled with the processed data.</p>
<p>You can chain multiple Promises, one after the other, until you get to the final value you need:</p>
<pre><code class="lang-javascript">readFile(<span class="hljs-string">'sourceData.json'</span>)
  .then(<span class="hljs-function"><span class="hljs-params">data</span> =&gt;</span> processData(data))
  .then(<span class="hljs-function"><span class="hljs-params">result</span> =&gt;</span> writeFile(result, <span class="hljs-string">'processedData.json'</span>))
  .then(<span class="hljs-function">() =&gt;</span> <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'Done processing'</span>));
</code></pre>
<p>In the above example, the whole expression will result in a Promise that won't be fulfilled until after the processed data is written to a file. "Done processing!" will be printed to the console, and then the final Promise will become fulfilled.</p>
<h3 id="heading-error-handling-in-promise-chains">Error handling in Promise chains</h3>
<p>In our file-processing example, an error can occur at any stage in the process. You can handle an error from any step in the Promise chain by using the Promise's <code>catch</code> method. </p>
<pre><code class="lang-javascript">readFile(<span class="hljs-string">'sourceData.json'</span>)
  .then(<span class="hljs-function"><span class="hljs-params">data</span> =&gt;</span> processData(data))
  .then(<span class="hljs-function"><span class="hljs-params">result</span> =&gt;</span> writeFile(result, <span class="hljs-string">'processedData.json'</span>))
  .then(<span class="hljs-function">() =&gt;</span> <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'Done processing'</span>))
  .catch(<span class="hljs-function"><span class="hljs-params">error</span> =&gt;</span> <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'Error while processing:'</span>, error));
</code></pre>
<p>If one of the Promises in the chain is rejected, the callback function passed to <code>catch</code> will execute and the rest of the chain is skipped.</p>
<h3 id="heading-how-to-use-finally">How to use <code>finally</code></h3>
<p>You might have some code you want to execute regardless of the Promise result. For example, maybe you want to close a database or a file.</p>
<pre><code class="lang-javascript">openDatabase()
  .then(<span class="hljs-function"><span class="hljs-params">data</span> =&gt;</span> processData(data))
  .catch(<span class="hljs-function"><span class="hljs-params">error</span> =&gt;</span> <span class="hljs-built_in">console</span>.error(<span class="hljs-string">'Error'</span>))
  .finally(<span class="hljs-function">() =&gt;</span> closeDatabase());
</code></pre>
<h3 id="heading-how-to-use-promiseall">How to use <code>Promise.all</code></h3>
<p>Promise chains let you run multiple tasks in sequence, but what if you want to run multiple tasks at the same time, and wait until they all complete? The <code>Promise.all</code> method lets you do just that.</p>
<p><code>Promise.all</code> takes an array of Promises, and returns a new Promise. This Promise will be fulfilled once all of the other Promises are fulfilled. The fulfillment value is an array containing the fulfillment values of each Promise in the input array.</p>
<p>Suppose you have a function <code>loadUserProfile</code> that loads a user's profile data, and  another function <code>loadUserPosts</code> that loads a user's posts. They both take a user ID as the argument. There's a third function, <code>renderUserPage</code>, that needs both the profile and list of posts.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> userId = <span class="hljs-number">100</span>;

<span class="hljs-keyword">const</span> profilePromise = loadUserProfile(userId);
<span class="hljs-keyword">const</span> postsPromise = loadUserPosts(userId);

<span class="hljs-built_in">Promise</span>.all([profilePromise, postsPromise])
  .then(<span class="hljs-function"><span class="hljs-params">results</span> =&gt;</span> {
    <span class="hljs-keyword">const</span> [profile, posts] = results;
    renderUserPage(profile, posts);
  });
</code></pre>
<p>What about errors? If any of the Promises passed to <code>Promise.all</code> is rejected with an error, the resulting Promise is also rejected with that error. If any of the other Promises are fulfilled, those values are lost.</p>
<h3 id="heading-how-to-use-promiseallsettled">How to use <code>Promise.allSettled</code></h3>
<p>The <code>Promise.allSettled</code> method works similarly to <code>Promise.all</code>. The main difference is that the Promise returned by <code>Promise.allSettled</code> will never be rejected. </p>
<p>Instead, it is fulfilled with an array of objects, whose order corresponds to the order of the Promises in the input array. Each object has a <code>status</code> property which is either "fulfilled" or "rejected", depending on the result. </p>
<p>If <code>status</code> is "fulfilled", the object will also have a <code>value</code> property indicating the Promise's fulfillment value. If <code>status</code> is "rejected", the object will instead have a <code>reason</code> property which is the error or other object the Promise was rejected with.</p>
<p>Consider again a <code>getUser</code> function that takes a user ID and returns a Promise that is fulfilled with the user having that ID. You can use <code>Promise.allSettled</code> to load these in parallel, making sure to get all users that were loaded successfully.</p>
<pre><code class="lang-javascript"><span class="hljs-built_in">Promise</span>.allSettled([
  getUser(<span class="hljs-number">1</span>),
  getUser(<span class="hljs-number">2</span>),
  getUser(<span class="hljs-number">3</span>)
]).then(<span class="hljs-function"><span class="hljs-params">results</span> =&gt;</span> {
   <span class="hljs-keyword">const</span> users = results
     .filter(<span class="hljs-function"><span class="hljs-params">result</span> =&gt;</span> result.status === <span class="hljs-string">'fulfilled'</span>)
     .map(<span class="hljs-function"><span class="hljs-params">result</span> =&gt;</span> result.value);
   <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'Got users:'</span>, users);
});
</code></pre>
<p>You can make a general purpose <code>loadUsers</code> function that loads users, in parallel, given an array of user IDs. The function returns a Promise that is fulfilled with an array of all users that were successfully loaded.</p>
<pre><code class="lang-javascript"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getUsers</span>(<span class="hljs-params">userIds</span>) </span>{
  <span class="hljs-keyword">return</span> <span class="hljs-built_in">Promise</span>.allSettled(userIds.map(<span class="hljs-function"><span class="hljs-params">id</span> =&gt;</span> getUser(id)))
    .then(<span class="hljs-function"><span class="hljs-params">results</span> =&gt;</span> {
      <span class="hljs-keyword">return</span> results
        .filter(<span class="hljs-function"><span class="hljs-params">result</span> =&gt;</span> result.status === <span class="hljs-string">'fulfilled'</span>)
        .map(<span class="hljs-function"><span class="hljs-params">result</span> =&gt;</span> result.value);
    });
}
</code></pre>
<p>Then, you can just call <code>getUsers</code> with an array of user IDs:</p>
<pre><code class="lang-javascript">getUsers([<span class="hljs-number">1</span>, <span class="hljs-number">2</span>, <span class="hljs-number">3</span>])
    .then(<span class="hljs-function"><span class="hljs-params">users</span> =&gt;</span> <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'Got users:'</span>, users));
</code></pre>
<h2 id="heading-how-to-create-immediately-fulfilled-or-rejected-promises">How to Create Immediately Fulfilled or Rejected Promises</h2>
<p>Sometimes, you may want to wrap a value in a fulfilled Promise. For example, maybe you have an asynchronous function that returns a Promise, but there is a base case where you know the value ahead of time and you don't need to do any asynchronous work.</p>
<p>To do this, you can call <code>Promise.resolve</code> with a value. This returns a Promise that is immediately fulfilled with the value you specified:</p>
<pre><code class="lang-javascript"><span class="hljs-built_in">Promise</span>.resolve(<span class="hljs-string">'hello'</span>)
  .then(<span class="hljs-function"><span class="hljs-params">result</span> =&gt;</span> {
    <span class="hljs-built_in">console</span>.log(result); <span class="hljs-comment">// prints "hello"</span>
  });
</code></pre>
<p>This is more or less equivalent to the following:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">new</span> <span class="hljs-built_in">Promise</span>(<span class="hljs-function"><span class="hljs-params">resolve</span> =&gt;</span> {
   resolve(<span class="hljs-string">'hello'</span>); 
}).then(<span class="hljs-function"><span class="hljs-params">result</span> =&gt;</span> {
    <span class="hljs-built_in">console</span>.log(result); <span class="hljs-comment">// also prints "hello"</span>
});
</code></pre>
<p>To make your API more consistent, you can create an immediately fulfilled Promise and return that in such cases. This way, the code that calls your function knows to always expect a Promise, no matter what.</p>
<p>For example, consider the <code>getUsers</code> function defined earlier. If the array of user IDs is empty, you could simply return an empty array because no users will be loaded.</p>
<pre><code class="lang-javascript"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getUsers</span>(<span class="hljs-params">userIds</span>) </span>{
  <span class="hljs-comment">// immediately return the empty array</span>
  <span class="hljs-keyword">if</span> (userIds.length === <span class="hljs-number">0</span>) {
    <span class="hljs-keyword">return</span> <span class="hljs-built_in">Promise</span>.resolve([]);
  }

  <span class="hljs-keyword">return</span> <span class="hljs-built_in">Promise</span>.allSettled(userIds.map(<span class="hljs-function"><span class="hljs-params">id</span> =&gt;</span> getUser(id)))
    .then(<span class="hljs-function"><span class="hljs-params">results</span> =&gt;</span> {
      <span class="hljs-keyword">return</span> results
        .filter(<span class="hljs-function"><span class="hljs-params">result</span> =&gt;</span> result.status === <span class="hljs-string">'fulfilled'</span>)
        .map(<span class="hljs-function"><span class="hljs-params">result</span> =&gt;</span> result.value);
    });
}
</code></pre>
<p>Another use for <code>Promise.resolve</code> is to handle the case where you are given a value that may or may not be a Promise, but you want to always treat it as a Promise. </p>
<p>You can safely call <code>Promise.resolve</code> on any value. If it was already a Promise, you'll just get another Promise that will have the same fulfillment or rejection value. If it was not a Promise, it will be wrapped in an immediately fulfilled Promise.</p>
<p>The benefit of this approach is you don't have to do something like this:</p>
<pre><code class="lang-javascript"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getResult</span>(<span class="hljs-params">result</span>) </span>{
  <span class="hljs-keyword">if</span> (result.then) {
     result.then(<span class="hljs-function"><span class="hljs-params">value</span> =&gt;</span> {
         <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'Result:'</span>, value);
     });
  } <span class="hljs-keyword">else</span> {
      <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'Result:'</span>, result);
  }
}
</code></pre>
<p>Similarly, you can create an immediately rejected Promise with <code>Promise.reject</code>. Returning once again to the <code>getUsers</code> function, maybe we want to immediately reject if the user ID array is <code>null</code>, <code>undefined</code>, or not an array.</p>
<pre><code class="lang-javascript"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getUsers</span>(<span class="hljs-params">userIds</span>) </span>{
  <span class="hljs-keyword">if</span> (userIds == <span class="hljs-literal">null</span> || !<span class="hljs-built_in">Array</span>.isArray(userIds)) {
    <span class="hljs-keyword">return</span> <span class="hljs-built_in">Promise</span>.reject(<span class="hljs-keyword">new</span> <span class="hljs-built_in">Error</span>(<span class="hljs-string">'User IDs must be an array'</span>));
  }

  <span class="hljs-comment">// immediately return the empty array</span>
  <span class="hljs-keyword">if</span> (userIds.length === <span class="hljs-number">0</span>) {
    <span class="hljs-keyword">return</span> <span class="hljs-built_in">Promise</span>.resolve([]);
  }

  <span class="hljs-keyword">return</span> <span class="hljs-built_in">Promise</span>.allSettled(userIds.map(<span class="hljs-function"><span class="hljs-params">id</span> =&gt;</span> getUser(id)))
    .then(<span class="hljs-function"><span class="hljs-params">results</span> =&gt;</span> {
      <span class="hljs-keyword">return</span> results
        .filter(<span class="hljs-function"><span class="hljs-params">result</span> =&gt;</span> result.status === <span class="hljs-string">'fulfilled'</span>)
        .map(<span class="hljs-function"><span class="hljs-params">result</span> =&gt;</span> result.value);
    });
}
</code></pre>
<h3 id="heading-how-to-use-promiserace">How to use <code>Promise.race</code></h3>
<p>Just like <code>Promise.all</code> or <code>Promise.allSettled</code>, the <code>Promise.race</code> static method takes an array of Promises, and returns a new Promise. As the name implies, though, it works somewhat differently.</p>
<p>The Promise returned by <code>Promise.race</code> will wait until the first of the given Promises is fulfilled or rejected, and then that Promise will also be fulfilled or rejected, with the same value. When this happens, the fulfilled or rejected values of the other Promises are lost.</p>
<h3 id="heading-how-to-use-promiseany">How to use <code>Promise.any</code></h3>
<p><code>Promise.any</code> works similarly to <code>Promise.race</code> with one key difference – where <code>Promise.race</code> will be done as soon as any Promise is fulfilled or rejected, <code>Promise.any</code> waits for the first <em>fulfilled</em> Promise.</p>
<h2 id="heading-how-to-use-async-and-await">How to Use <code>async</code> and <code>await</code></h2>
<p><code>async</code> and <code>await</code> are special keywords that simplify working with Promises. They remove the need for callback functions and calls to <code>then</code> or <code>catch</code>. They work with try-catch blocks, as well.</p>
<p>Here's how it works. Instead of calling <code>then</code> on a Promise, you <code>await</code> it by putting the <code>await</code> keyword before it. This effectively "pauses" execution of the function until the Promise is fulfilled.</p>
<p>Here's an example using standard Promises:</p>
<pre><code class="lang-javascript">getUsers().then(<span class="hljs-function"><span class="hljs-params">users</span> =&gt;</span> {
    <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'Got users:'</span>, users);
});
</code></pre>
<p>Here's the equivalent code using the <code>await</code> keyword:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> users = <span class="hljs-keyword">await</span> getUsers();
<span class="hljs-built_in">console</span>.log(<span class="hljs-string">'Got users:'</span>, users);
</code></pre>
<p>Promise chains are a little cleaner, too:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> data = <span class="hljs-keyword">await</span> readFile(<span class="hljs-string">'sourceData.json'</span>);
<span class="hljs-keyword">const</span> result = <span class="hljs-keyword">await</span> processData(data);
<span class="hljs-keyword">await</span> writeFile(result, <span class="hljs-string">'processedData.json'</span>);
</code></pre>
<p>Remember that each usage of <code>await</code> will pause execution of the rest of the function until the Promise you are awaiting becomes fulfilled. If you want to await several Promises that run in parallel, you can use <code>Promise.all</code>:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> users = <span class="hljs-keyword">await</span> <span class="hljs-built_in">Promise</span>.all([getUser(<span class="hljs-number">1</span>), getUser(<span class="hljs-number">2</span>), getUser(<span class="hljs-number">3</span>)]);
</code></pre>
<p>To use the <code>await</code> keyword, your function must be marked as an async function. You can do this by placing the <code>async</code> keyword before your function:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">processData</span>(<span class="hljs-params">sourceFile, outputFile</span>) </span>{
  <span class="hljs-keyword">const</span> data = <span class="hljs-keyword">await</span> readFile(sourceFile);
  <span class="hljs-keyword">const</span> result = <span class="hljs-keyword">await</span> processData(data);
  writeFile(result, outputFile);
}
</code></pre>
<p>Adding the <code>async</code> keyword also has another important effect on the function. Async functions always implicitly return a Promise. If you return a value from an async function, the function will actually return a Promise that is fulfilled with that value.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">add</span>(<span class="hljs-params">a, b</span>) </span>{
  <span class="hljs-keyword">return</span> a + b;   
}

add(<span class="hljs-number">2</span>, <span class="hljs-number">3</span>).then(<span class="hljs-function"><span class="hljs-params">sum</span> =&gt;</span> {
   <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'Sum is:'</span>, sum); 
});
</code></pre>
<p>In the above example, the function is returning the sum of the two arguments <code>a</code> and <code>b</code>. But since it's an <code>async</code> function, it doesn't return the sum but rather a Promise that is fulfilled with the sum.</p>
<h3 id="heading-error-handling-with-async-and-await">Error handling with <code>async</code> and <code>await</code></h3>
<p>We use <code>await</code> to wait for Promise to be fulfilled, but what about handling errors? If you are awaiting a Promise, and it is rejected, an error will be thrown. This means to handle the error, you can put it in a try-catch block:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">try</span> {
    <span class="hljs-keyword">const</span> data = <span class="hljs-keyword">await</span> readFile(sourceFile);
    <span class="hljs-keyword">const</span> result = <span class="hljs-keyword">await</span> processData(data);
    <span class="hljs-keyword">await</span> writeFile(result, outputFile);
} <span class="hljs-keyword">catch</span> (error) {
    <span class="hljs-built_in">console</span>.error(<span class="hljs-string">'Error occurred while processing:'</span>, error);
}
</code></pre>
<h2 id="heading-promise-anti-patterns">Promise Anti-Patterns</h2>
<h3 id="heading-unnecessarily-creating-a-new-promise">Unnecessarily creating a new Promise</h3>
<p>Sometimes there's no getting around creating a new Promise. But if you are already working with Promises returned by an API, you usually shouldn't need to create your own Promise:</p>
<pre><code class="lang-javascript"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getUsers</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">Promise</span>(<span class="hljs-function"><span class="hljs-params">resolve</span> =&gt;</span> {
     fetch(<span class="hljs-string">'https://example.com/api/users'</span>)
       .then(<span class="hljs-function"><span class="hljs-params">result</span> =&gt;</span> result.json())
       .then(<span class="hljs-function"><span class="hljs-params">data</span> =&gt;</span> resolve(data))
  });
}
</code></pre>
<p>In this example, we're creating a new Promise to wrap the Fetch API, which already returns Promises. This is unnecessary. Instead, just return the Promise chain from the Fetch API directly:</p>
<pre><code class="lang-javascript"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getUsers</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">return</span> fetch(<span class="hljs-string">'https://example.com/api/users'</span>)
    .then(<span class="hljs-function"><span class="hljs-params">result</span> =&gt;</span> result.json());
}
</code></pre>
<p>In both cases, the code calling <code>getUsers</code> looks the same:</p>
<pre><code class="lang-javascript">getUsers()
  .then(<span class="hljs-function"><span class="hljs-params">users</span> =&gt;</span> <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'Got users:'</span>, users))
  .catch(<span class="hljs-function"><span class="hljs-params">error</span> =&gt;</span> <span class="hljs-built_in">console</span>.error(<span class="hljs-string">'Error fetching users:'</span>, error));
</code></pre>
<h3 id="heading-swallowing-errors">Swallowing errors</h3>
<p>Consider this version of a <code>getUsers</code> function:</p>
<pre><code class="lang-javascript"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getUsers</span>(<span class="hljs-params"></span>) </span>{
    <span class="hljs-keyword">return</span> fetch(<span class="hljs-string">'https://example.com/api/users'</span>)
        .then(<span class="hljs-function"><span class="hljs-params">result</span> =&gt;</span> result.json())
        .catch(<span class="hljs-function"><span class="hljs-params">error</span> =&gt;</span> <span class="hljs-built_in">console</span>.error(<span class="hljs-string">'Error loading users:'</span>, error));
}
</code></pre>
<p>Error handling is good, right? You might be surprised by the result if we call this <code>getUsers</code> function:</p>
<pre><code class="lang-javascript">getUsers()
  .then(<span class="hljs-function"><span class="hljs-params">users</span> =&gt;</span> <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'Got users:'</span>, users))
  .catch(<span class="hljs-function"><span class="hljs-params">error</span> =&gt;</span> <span class="hljs-built_in">console</span>.error(<span class="hljs-string">'error:'</span>, error);)
</code></pre>
<p>You might expect this to print "error", but it will actually print "Got users: undefined". This is because the <code>catch</code> call "swallows" the error and returns a new Promise that is fulfilled with the return value of the <code>catch</code> callback, which is <code>undefined</code> (<code>console.error</code> returns <code>undefined</code>). You'll still see the "Error loading users" log message from <code>getUsers</code>, but the returned Promise will be fulfilled, not rejected.</p>
<p>If you want to catch the error inside the <code>getUsers</code> function and still reject the returned Promise, the <code>catch</code> handler needs to return a rejected Promise. You can do this by using <code>Promise.reject</code>.</p>
<pre><code class="lang-javascript"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getUsers</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">return</span> fetch(<span class="hljs-string">'https://example.com/api/users'</span>)
    .then(<span class="hljs-function"><span class="hljs-params">result</span> =&gt;</span> result.json())
    .catch(<span class="hljs-function"><span class="hljs-params">error</span> =&gt;</span> {
      <span class="hljs-built_in">console</span>.error(<span class="hljs-string">'Error loading users:'</span>, error);
      <span class="hljs-keyword">return</span> <span class="hljs-built_in">Promise</span>.reject(error);
    });
}
</code></pre>
<p>Now you'll still get the "Error loading users" message, but the returned Promise will also be rejected with the error.</p>
<h3 id="heading-nesting-promises">Nesting Promises</h3>
<p>Avoid nesting Promise code. Instead, try to use flattened Promise chains.</p>
<p>Instead of this:</p>
<pre><code class="lang-javascript">readFile(sourceFile)
  .then(<span class="hljs-function"><span class="hljs-params">data</span> =&gt;</span> {
    processData(data)
      .then(<span class="hljs-function"><span class="hljs-params">result</span> =&gt;</span> {
        writeFile(result, outputFile)
          .then(<span class="hljs-function">() =&gt;</span> <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'done'</span>);
      });
  });
</code></pre>
<p>Do this:</p>
<pre><code class="lang-javascript">readFile(sourceFile)
  .then(<span class="hljs-function"><span class="hljs-params">data</span> =&gt;</span> processData(data))
  .then(<span class="hljs-function"><span class="hljs-params">result</span> =&gt;</span> writeFile(result, outputFile))
  .then(<span class="hljs-function">() =&gt;</span> <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'done'</span>));
</code></pre>
<h2 id="heading-summary">Summary</h2>
<p>Here are the key points for working with Promises:</p>
<ul>
<li>A Promise can be pending, fulfilled, or rejected</li>
<li>A Promise is settled if it is either fulfilled or rejected</li>
<li>Use <code>then</code> to get the fulfilled value of a Promise</li>
<li>Use <code>catch</code> to handle errors</li>
<li>Use <code>finally</code> to perform cleanup logic that you need in either the success or error case</li>
<li>Chain Promises together to perform asynchronous tasks in sequence</li>
<li>Use <code>Promise.all</code> to get a Promise that is fulfilled when all given Promises are fulfilled, or rejects when one of those Promises rejects</li>
<li>Use <code>Promise.allSettled</code> to get a Promise that is fulfilled when all given Promises are either fulfilled or rejected</li>
<li>Use <code>Promise.race</code> to get a Promise that is fulfilled or rejected when the first of the given Promises is either fulfilled or rejected</li>
<li>Use <code>Promise.any</code> to get a Promise that is fulfilled when the first of the given Promises is fulfilled</li>
<li>Use the <code>await</code> keyword to wait for the fulfillment value of a Promise</li>
<li>Use a try-catch block to handle errors when using the <code>await</code> keyword</li>
<li>A function that uses <code>await</code> inside of it must use the <code>async</code> keyword</li>
</ul>
<p>Thank you for reading this deep dive on Promises. I hope you learned something new!</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Center Text Vertically with CSS ]]>
                </title>
                <description>
                    <![CDATA[ If you have some text inside a div, and nothing else, the div's height will match the text height. Suppose, though, you have some text and an image. Your text will be aligned at the bottom of the div, which is usually not what you want. In this artic... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-center-text-vertically-with-css/</link>
                <guid isPermaLink="false">66ba5659efd5e6f1088c7298</guid>
                
                    <category>
                        <![CDATA[ CSS ]]>
                    </category>
                
                    <category>
                        <![CDATA[ CSS Grid ]]>
                    </category>
                
                    <category>
                        <![CDATA[ flexbox ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Web Development ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Joe Attardi ]]>
                </dc:creator>
                <pubDate>Mon, 23 Oct 2023 19:44:32 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2023/10/pexels-alexander-ermakov-12154194.jpg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>If you have some text inside a <code>div</code>, and nothing else, the <code>div</code>'s height will match the text height. Suppose, though, you have some text and an image. Your text will be aligned at the bottom of the <code>div</code>, which is usually not what you want.</p>
<p>In this article, you'll learn a couple of ways to vertically center your text inside such a <code>div</code> or other element.</p>
<h2 id="heading-how-to-center-text-using-line-height">How to Center Text using Line Height</h2>
<p>This approach is limited, but can be useful if you have your element set to a fixed height using the <code>height</code> property.</p>
<p>The <code>line-height</code> property determines the height of the box that the browser renders text into. By default, this is set to a value slightly larger than 1 to provide comfortable spacing between lines of text.</p>
<p>If you set the element's <code>height</code> and <code>line-height</code> to the same value, the text will be vertically centered:</p>
<pre><code class="lang-css"><span class="hljs-selector-class">.my-element</span> {
  <span class="hljs-attribute">height</span>: <span class="hljs-number">3rem</span>;
  <span class="hljs-attribute">line-height</span>: <span class="hljs-number">3rem</span>;
}
</code></pre>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/10/image-91.png" alt="Image" width="600" height="400" loading="lazy">
<em>Vertically centered text using line-height</em></p>
<p>There is an important caveat to this approach, though. This only works if your text can fit on one line.</p>
<p>If the text does wrap, you'll see the first line vertically centered. Because you set the <code>line-height</code> to be the same as the element's <code>height</code>, the wrapped line of text now overflows the element.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/10/image-94.png" alt="Image" width="600" height="400" loading="lazy">
<em>Wrapped text overflowing the container</em></p>
<p>If this sounds too rigid, read on. Next, you'll see how you can use Flexbox to vertically center your text, along with any other content inside the element.</p>
<h2 id="heading-how-to-center-text-using-flexbox">How to Center Text using Flexbox</h2>
<p>A better, more general-purpose solution, is to use a Flexbox layout with <code>align-items</code> set to <code>center</code>.</p>
<p>An element using Flexbox (the flex container) lays out elements (flex items) either in a row or column. A Flexbox layout has two imaginary lines running through it. The first is the <em>main</em> axis, along which items will be placed. For a <code>row</code> flexbox, the main axis is the horizontal axis.</p>
<p>The <em>cross</em> axis runs perpendicular to the main axis. You can use the cross axis to define the vertical alignment of elements inside the flex container.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/10/image-92.png" alt="Image" width="600" height="400" loading="lazy">
<em>The main and cross axis in a horizontal Flexbox layout</em></p>
<p>Here's the CSS you'll need to apply a Flexbox layout and vertically center the text:</p>
<pre><code class="lang-css"><span class="hljs-selector-class">.my-element</span> {
    <span class="hljs-comment">/* Use a flexbox layout */</span>
    <span class="hljs-attribute">display</span>: flex;

    <span class="hljs-comment">/* Make a horizontal flexbox (the default) */</span>
    <span class="hljs-attribute">flex-direction</span>: row;

    <span class="hljs-comment">/* The important part: vertically center the items */</span>
    <span class="hljs-attribute">align-items</span>: center;
}
</code></pre>
<p>This creates a horizontal Flexbox layout (the <code>flex-direction: row</code> is not strictly required, as it's the default). The <code>align-items</code> property determines the alignment of items along the cross, or vertical, axis. There are a few different values you can use, but here you can use <code>center</code> to vertically center the text.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/10/image-96.png" alt="Image" width="600" height="400" loading="lazy">
<em>The text with align-items: center</em></p>
<p>This works nicely, and it even handles multiple lines of wrapped text. If you have other content inside the element, such as an image, everything will be aligned vertically.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/10/image-95.png" alt="Image" width="600" height="400" loading="lazy">
<em>The text is aligned vertically with other content</em></p>
<h2 id="heading-how-to-center-text-using-css-grid">How to Center Text Using CSS Grid</h2>
<p>You can also center your content vertically using CSS Grid. </p>
<p>For a single <code>div</code> containing the text to center, you can turn it into a grid layout with one row and one column.</p>
<pre><code class="lang-css"><span class="hljs-selector-class">.my-element</span> {
    <span class="hljs-attribute">display</span>: grid;
    <span class="hljs-attribute">align-items</span>: center;
}
</code></pre>
<p>In a grid layout, the <code>align-items</code> property specifies the alignment of the content within the cell, along the column (vertical) axis. This vertically aligns your text within the <code>div</code> element.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/10/image-98.png" alt="Image" width="600" height="400" loading="lazy">
<em>Text vertically centered using a 1x1 grid layout</em></p>
<p>If the element containing your text is already part of a grid layout, you can either apply <code>align-items: center</code> to the entire grid, or if you just want to control the vertical alignment of that one grid cell, you can use <code>align-self: center</code>.</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>Now you know how to vertically center text. Next time you see a tweet about centering a <code>div</code>, you can reply with your newfound CSS knowledge!</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Build Your First Web Component ]]>
                </title>
                <description>
                    <![CDATA[ In 2023, browser support for web components (also known as custom elements) is really good. There's never been a better time to start building your own custom elements. Web components, also known as custom elements, are new HTML elements that you cre... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/build-your-first-web-component/</link>
                <guid isPermaLink="false">66ba5655bab56b945824000f</guid>
                
                    <category>
                        <![CDATA[ components ]]>
                    </category>
                
                    <category>
                        <![CDATA[ HTML ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Web Development ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Joe Attardi ]]>
                </dc:creator>
                <pubDate>Thu, 19 Oct 2023 20:35:35 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2023/10/pexels-just-another-photography-dude-68725.jpg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>In 2023, browser support for web components (also known as custom elements) is really good. There's never been a better time to start building your own custom elements.</p>
<p>Web components, also known as custom elements, are new HTML elements that you create. These elements encapsulate some markup, style, and interactivity. </p>
<p>In this article, you'll learn the basics of web components and create a very simple web component that shows the current date.</p>
<p>This guide is intended as a gentle introduction to the concept, so it won't cover some more advanced aspects such as templates, slots, or shadow DOM. But, these are all powerful building blocks to building components that you should learn as you ramp up your skills.</p>
<h2 id="heading-what-is-a-web-component">What is a Web Component?</h2>
<p>A web component is a custom HTML element that you define, with its own tag name. Think of it as an encapsulated, reusable piece of code. Just like regular HTML elements, web components can accept attributes and you can listen for events.</p>
<p>Web components are a nice way to add some extra functionality to your web app. Since it's a web standard, there's no extra third-party code needed.</p>
<p>A web component can be as simple or complex as you want: it can simply display some text (as the example in this article will be doing), or it can be highly interactive. </p>
<h2 id="heading-web-component-basics">Web Component Basics</h2>
<p>To define a web component, create a class that extends from <code>HTMLElement</code>. This class will contain all of your web component's behavior. After that, you need to register it with the browser by calling <code>customElements.define</code>.</p>
<pre><code class="lang-javascript"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">MyComponent</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">HTMLElement</span> </span>{
    <span class="hljs-comment">// component implementation goes here</span>
}

customElements.define(<span class="hljs-string">'my-component'</span>, MyComponent);
</code></pre>
<p>Once you've done this, you can use your component by just adding a <code>&lt;my-component&gt;</code> element to your HTML. That's it! You've just added a web component to your page.</p>
<p>Note that the component name has a hyphen. This is required by the specification, to prevent name clashes with potential future standard HTML elements.</p>
<h3 id="heading-lifecycle-callbacks">Lifecycle callbacks</h3>
<p>Web components have a few lifecycle callbacks. These are functions that the browser calls at different parts of the component's lifecycle. Some of these callbacks are:</p>
<ul>
<li><code>connectedCallback</code>: Called when the element is first added to the DOM</li>
<li><code>disconnectedCallback</code>: Called when the element is removed from the DOM</li>
<li><code>attributeChangedCallback</code>: Called when one of the element's watched attributes change. For an attribute to be watched, you must add it to the component class's static <code>observedAttributes</code> property.</li>
</ul>
<p>For this simple component, you'll only need the <code>connectedCallback</code>. </p>
<h2 id="heading-how-to-create-the-component">How to Create the Component</h2>
<p>In a new JavaScript file, create the component class and add the call to <code>customElements.define</code> as shown above. Here's the first pass at the <code>CurrentDate</code> component:</p>
<pre><code class="lang-javascript"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">CurrentDate</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">HTMLElement</span> </span>{
    <span class="hljs-comment">// The browser calls this method when the element is</span>
    <span class="hljs-comment">// added to the DOM.</span>
    connectedCallback() {
        <span class="hljs-comment">// Create a Date object representing the current date.</span>
        <span class="hljs-keyword">const</span> now = <span class="hljs-keyword">new</span> <span class="hljs-built_in">Date</span>();

        <span class="hljs-comment">// Format the date to a human-friendly string, and set the</span>
        <span class="hljs-comment">// formatted date as the text content of this element.</span>
        <span class="hljs-built_in">this</span>.textContent = now.toLocaleDateString();
    }
}

<span class="hljs-comment">// Register the CurrentDate component using the tag name &lt;current-date&gt;.</span>
customElements.define(<span class="hljs-string">'current-date'</span>, CurrentDate);
</code></pre>
<p>In the <code>connectedCallback</code>, you are getting the current date and calling <code>toLocaleDateString</code>, which formats the date portion of the <code>Date</code> object in a more human friendly format. For example, in the <code>en-US</code> locale, this would be a format like <code>10/18/2023</code>.</p>
<p>There are no event listeners to clean up here, so there is no need for a <code>disconnectedCallback</code>.</p>
<p>Since <code>CurrentDate</code> extends from <code>HTMLElement</code>, it includes all of its properties and methods. This is why you can use the <code>textContent</code> property like with any other HTML element. This will set the formatted date as the value of a text node inside the <code>&lt;current-date&gt;</code> element.</p>
<h2 id="heading-how-to-use-the-component">How to Use the Component</h2>
<p>Before you use the component, you need to load it using an <code>import</code> statement or a <code>script</code> tag. Here's a simple usage example using a <code>script</code> tag:</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">script</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"./currentDate.js"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span>

<span class="hljs-tag">&lt;<span class="hljs-name">h2</span>&gt;</span>Today's Date<span class="hljs-tag">&lt;/<span class="hljs-name">h2</span>&gt;</span>
The current date is: <span class="hljs-tag">&lt;<span class="hljs-name">current-date</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">current-date</span>&gt;</span>
</code></pre>
<p>Note that custom elements, even when they have no child content, cannot use the self-closing tag syntax supported by some elements. They must always have an explicit closing tag.</p>
<h2 id="heading-future-enhancements">Future Enhancements</h2>
<p>Here are some ways you can enhance the <code>CurrentDate</code> component:</p>
<ul>
<li>Use <code>Intl.DateTimeFormat</code> to create a more human-readable format for the date. You could even add attributes to customize the date format used.</li>
<li>Add support for a <code>date</code> attribute and adapt the component so that it can display any arbitrary date, not just the current date. Of course, in this case, you'll want to change the name from <code>CurrentDate</code> to something else like <code>FormattedDate</code>.</li>
<li>Use the HTML <code>time</code> element inside the component to produce more semantic markup</li>
</ul>
<h2 id="heading-conclusion">Conclusion</h2>
<p>In this article, you took your first step into the world of web components. </p>
<p>Web components have no third party dependencies, so using them won't have a big impact on your bundle size. But for more complex components, you may want to reach for a library like Svelte or Lit.</p>
 ]]>
                </content:encoded>
            </item>
        
    </channel>
</rss>
