Supercharge Your React Apps with ‘React-Helmet’: A Practical Guide for Developers

In the ever-evolving landscape of web development, optimizing your React applications for search engines and social media is crucial. A well-optimized application not only enhances user experience but also improves its visibility, driving organic traffic and engagement. One of the key aspects of SEO and social sharing is managing the HTML “ section of your application. This is where meta tags, title tags, and other important information reside, telling search engines and social platforms what your page is about. Manually manipulating the “ section in a React application can be cumbersome and error-prone. This is where `react-helmet` comes in, offering a simple yet powerful solution to dynamically manage your document head.

What is React-Helmet?

`React-Helmet` is a third-party npm package that allows you to control your document head from within your React components. It provides a declarative way to manage all of your “ tags, including ``, “, “, and more. This means you can easily update these tags based on your application’s state or the currently displayed content. `React-Helmet` is incredibly versatile and can be used to:</p> <ul> <li>Set the page title dynamically.</li> <li>Add meta descriptions and keywords for SEO.</li> <li>Manage Open Graph tags for social media sharing.</li> <li>Include custom CSS and JavaScript.</li> <li>Control the character set and viewport settings.</li> </ul> <h2>Why Use React-Helmet?</h2> <p>While you <em>could</em> manually manipulate the document head using JavaScript, `React-Helmet` offers several advantages:</p> <ul> <li><strong>Declarative Approach:</strong> You define the head elements within your components, making your code more readable and maintainable.</li> <li><strong>Server-Side Rendering (SSR) Compatibility:</strong> `React-Helmet` works seamlessly with SSR frameworks like Next.js and Gatsby, ensuring that your meta tags are rendered correctly on the server. This is essential for SEO, as search engine crawlers can access the complete HTML content.</li> <li><strong>Component-Based:</strong> You can easily manage head elements on a per-component basis, making it simple to tailor the head content to each page or section of your application.</li> <li><strong>Performance:</strong> `React-Helmet` optimizes the process of updating the head, minimizing unnecessary DOM manipulations.</li> </ul> <h2>Getting Started with React-Helmet</h2> <p>Let’s dive into how to use `react-helmet` in your React project. First, you need to install it:</p> <pre><code class="language-bash" data-line="">npm install react-helmet</code></pre> <p>Or, if you’re using yarn:</p> <pre><code class="language-bash" data-line="">yarn add react-helmet</code></pre> <p>Once installed, you can import `Helmet` from the `react-helmet` package and use it within your components. Here’s a basic example:</p> <pre><code class="language-jsx" data-line="">import React from 'react'; import { Helmet } from 'react-helmet'; function MyComponent() { return ( <div> <Helmet> <title>My Awesome Page</title> <meta name="description" content="This is a description of my awesome page." /> </Helmet> <h1>Hello, World!</h1> <p>This is some content.</p> </div> ); } export default MyComponent;</code></pre> <p>In this example:</p> <ul> <li>We import `Helmet` from `react-helmet`.</li> <li>We wrap the head elements (title and meta description) inside the `<Helmet>` component.</li> <li>The `<title>` tag sets the page title.</li> <li>The `<meta>` tag sets the meta description.</li> </ul> <p>When this component is rendered, `react-helmet` will update the document head with the specified title and meta description.</p> <h2>Advanced Usage: Dynamic Titles and Meta Tags</h2> <p>One of the most powerful features of `react-helmet` is its ability to dynamically update the head based on your component’s state or props. This is incredibly useful for setting page titles and meta descriptions that reflect the content currently being displayed. Let’s look at an example:</p> <pre><code class="language-jsx" data-line="">import React, { useState, useEffect } from 'react'; import { Helmet } from 'react-helmet'; function BlogPost({ title, content }) { const [pageTitle, setPageTitle] = useState(title); useEffect(() => { setPageTitle(title); }, [title]); return ( <div> <Helmet> <title>{pageTitle}</title> <meta name="description" content={`Read about ${title}`} /> </Helmet> <h1>{title}</h1> <p>{content}</p> </div> ); } export default BlogPost;</code></pre> <p>In this example:</p> <ul> <li>The `BlogPost` component receives a `title` prop.</li> <li>We use the `title` prop to set the page title dynamically.</li> <li>The meta description also uses the `title` prop to provide a relevant description.</li> <li>The `useEffect` hook ensures that the `pageTitle` is updated whenever the `title` prop changes.</li> </ul> <p>This allows you to change the title and description of the page based on the specific blog post being viewed.</p> <h2>Working with Open Graph Tags</h2> <p>Open Graph tags are essential for social media sharing. They provide information to social platforms like Facebook and Twitter about how to display your content when it’s shared. `React-Helmet` makes it easy to add Open Graph tags:</p> <pre><code class="language-jsx" data-line="">import React from 'react'; import { Helmet } from 'react-helmet'; function SocialShare({ title, description, imageUrl }) { return ( <Helmet> <meta property="og:title" content={title} /> <meta property="og:description" content={description} /> <meta property="og:image" content={imageUrl} /> <meta property="og:url" content="https://www.example.com/blog/" /> <meta property="og:type" content="article" /> </Helmet> ); } export default SocialShare;</code></pre> <p>In this example:</p> <ul> <li>We use the `property` attribute to specify the Open Graph tag.</li> <li>`og:title`, `og:description`, `og:image`, `og:url`, and `og:type` are common Open Graph properties.</li> <li>We pass the necessary data (title, description, image URL) as props to the component.</li> </ul> <p>When this component is rendered, `react-helmet` will add the specified Open Graph tags to the document head, allowing social media platforms to display your content correctly.</p> <h2>Adding Link Tags and Stylesheets</h2> <p>`React-Helmet` isn’t limited to just meta tags and titles. You can also use it to add “ tags for stylesheets, favicons, and other resources.</p> <pre><code class="language-jsx" data-line="">import React from 'react'; import { Helmet } from 'react-helmet'; function MyComponent() { return ( <div> <Helmet> <link rel="stylesheet" href="/styles.css" /> <link rel="icon" href="/favicon.ico" /> </Helmet> <h1>Hello, World!</h1> <p>This is some content.</p> </div> ); } export default MyComponent;</code></pre> <p>In this example:</p> <ul> <li>We use the `<link>` tag to include a stylesheet and a favicon.</li> <li>The `rel` attribute specifies the relationship of the linked resource (stylesheet or icon).</li> <li>The `href` attribute specifies the URL of the resource.</li> </ul> <p>This allows you to manage your application’s styling and other linked resources directly from your React components.</p> <h2>Managing Multiple Instances of Helmet</h2> <p>You can use multiple instances of the `Helmet` component throughout your application. This is particularly useful when you have nested components that need to manage their own head elements. `React-Helmet` intelligently merges the head elements from all instances, ensuring that everything is rendered correctly.</p> <pre><code class="language-jsx" data-line="">import React from 'react'; import { Helmet } from 'react-helmet'; function ParentComponent() { return ( <div> <Helmet> <title>Parent Title</title> </Helmet> <ChildComponent /> </div> ); } function ChildComponent() { return ( <div> <Helmet> <meta name="description" content="Child Description" /> </Helmet> <h2>Child Component</h2> </div> ); } export default ParentComponent;</code></pre> <p>In this example, the final document head will include both the title from the `ParentComponent` and the meta description from the `ChildComponent`.</p> <h2>Common Mistakes and How to Fix Them</h2> <p>Here are some common mistakes developers make when using `react-helmet` and how to avoid them:</p> <ol> <li><strong>Forgetting to Import Helmet:</strong> Make sure you import `Helmet` from `react-helmet` at the top of your component file. This is a simple but common oversight.</li> <li><strong>Incorrect Attribute Names:</strong> Double-check that you’re using the correct attribute names for your meta tags and other head elements (e.g., `name` for the `meta` tag’s name attribute, `property` for Open Graph properties).</li> <li><strong>Conflicting Meta Tags:</strong> If you have multiple `Helmet` components with conflicting meta tags (e.g., two different descriptions), `react-helmet` will typically merge them, but it’s best to avoid conflicts by carefully planning your head elements.</li> <li><strong>Not Using Dynamic Values:</strong> Don’t hardcode values that should change based on your component’s state or props. Use JavaScript expressions (e.g., `{title}`) to dynamically set the head elements.</li> <li><strong>Missing Server-Side Rendering Setup:</strong> If you’re using SSR, make sure you’ve configured your framework (e.g., Next.js, Gatsby) to handle `react-helmet` correctly. This typically involves using the `HelmetProvider` component. Failing to set up SSR correctly will result in SEO issues.</li> </ol> <h2>Best Practices for SEO with React-Helmet</h2> <p>While `react-helmet` simplifies the process of managing your document head, it’s essential to follow SEO best practices to maximize your application’s visibility:</p> <ul> <li><strong>Use Descriptive Titles:</strong> Your title tags should accurately reflect the content of each page. Include relevant keywords, but avoid keyword stuffing.</li> <li><strong>Write Compelling Meta Descriptions:</strong> Meta descriptions should entice users to click on your search result. Keep them concise and informative.</li> <li><strong>Optimize Open Graph Tags:</strong> Ensure your Open Graph tags are set up correctly for social media sharing. Use high-quality images and compelling descriptions.</li> <li><strong>Use Keywords Strategically:</strong> Include relevant keywords in your title tags, meta descriptions, and content, but avoid overusing them. Focus on creating high-quality, informative content.</li> <li><strong>Ensure Mobile-Friendliness:</strong> Make sure your application is responsive and works well on all devices.</li> <li><strong>Submit a Sitemap:</strong> Submit a sitemap to search engines to help them crawl and index your content.</li> <li><strong>Monitor Your Rankings:</strong> Use tools like Google Search Console to monitor your website’s performance and identify areas for improvement.</li> </ul> <h2>React-Helmet vs. Other Solutions</h2> <p>While `react-helmet` is a popular and effective choice, there are other ways to manage your document head in React:</p> <ul> <li><strong>Manual DOM Manipulation:</strong> You can manually update the document head using JavaScript, but this approach is less maintainable and can be more prone to errors.</li> <li><strong>Other Third-Party Libraries:</strong> There are other libraries available, but `react-helmet` is generally considered the most mature and widely used.</li> <li><strong>Framework-Specific Solutions:</strong> Some frameworks (e.g., Next.js) have built-in solutions for managing the document head. However, `react-helmet` is still a viable option and can be used with these frameworks.</li> </ul> <p>The choice of which solution to use depends on your specific needs and preferences. `React-Helmet` offers a good balance of simplicity, flexibility, and performance.</p> <h2>Summary / Key Takeaways</h2> <p>In this tutorial, we’ve explored how to use `react-helmet` to manage the document head in your React applications. We’ve covered the basics of installation and usage, demonstrated how to dynamically set titles and meta tags, and discussed how to integrate Open Graph tags. We’ve also highlighted common mistakes and best practices for SEO. Here are the key takeaways:</p> <ul> <li>`React-Helmet` simplifies the process of managing your document head.</li> <li>You can dynamically update head elements based on your component’s state or props.</li> <li>It’s essential for SEO and social media sharing.</li> <li>Make sure you follow SEO best practices.</li> </ul> <h2>FAQ</h2> <p>Here are some frequently asked questions about `react-helmet`:</p> <ol> <li><strong>Does `react-helmet` work with server-side rendering (SSR)?</strong><br /> Yes, `react-helmet` is designed to work seamlessly with SSR frameworks like Next.js and Gatsby. However, you need to configure your framework to handle it correctly, typically by using the `HelmetProvider` component.</li> <li><strong>Can I use multiple instances of `Helmet` in my application?</strong><br /> Yes, you can use multiple instances of `Helmet` throughout your application. `React-Helmet` intelligently merges the head elements from all instances.</li> <li><strong>How do I handle conflicting meta tags?</strong><br /> `React-Helmet` typically merges conflicting meta tags, but it’s best to avoid conflicts by carefully planning your head elements. If conflicts occur, the last defined tag usually takes precedence.</li> <li><strong>Is `react-helmet` the only way to manage the document head in React?</strong><br /> No, there are other ways, such as manual DOM manipulation or other third-party libraries. However, `react-helmet` is a popular and effective choice due to its simplicity, flexibility, and performance.</li> <li><strong>How do I debug issues with `react-helmet`?</strong><br /> Inspect the rendered HTML of your page in your browser’s developer tools to verify that the head elements are being rendered correctly. Check the console for any errors or warnings. Also, ensure that you’ve correctly configured your SSR setup if you’re using it.</li> </ol> <p>By leveraging `react-helmet`, developers can ensure their React applications are well-optimized for search engines and social media, improving their online presence and user engagement. From setting dynamic titles and meta descriptions to managing Open Graph tags and linking to stylesheets, `react-helmet` offers a comprehensive solution for controlling your document head. Its ease of use, compatibility with server-side rendering, and component-based approach make it an indispensable tool for any React developer looking to build a high-performing and SEO-friendly web application. The journey to a well-optimized React application begins with a solid foundation, and `react-helmet` provides that foundation for managing the crucial “ section of your HTML documents, paving the way for improved search engine rankings, increased organic traffic, and a more engaging user experience.</p> <div class="wpzoom-social-sharing-buttons-bottom"><div class="wp-block-wpzoom-blocks-social-sharing align-none"><ul class="social-sharing-icons"><li class="social-sharing-icon-li"><a class="social-sharing-icon social-sharing-icon-facebook" style="padding:5px 15px;margin:5px 5px;border-radius:50px;font-size:20px;color:#ffffff;background-color:#0866FF;" href="https://www.facebook.com/sharer/sharer.php?u=https%3A%2F%2Flearnmodernjavascript.com%2Fsupercharge-your-react-apps-with-react-helmet-a-practical-guide-for-developers%2F&t=Supercharge+Your+React+Apps+with+%26%238216%3BReact-Helmet%26%238217%3B%3A+A+Practical+Guide+for+Developers" title="Facebook" target="_blank" rel="noopener noreferrer" data-platform="facebook"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="20" height="20" style="fill:#ffffff;" aria-hidden="true" focusable="false"><path d="M24 12.073c0-6.627-5.373-12-12-12s-12 5.373-12 12c0 5.99 4.388 10.954 10.125 11.854v-8.385H7.078v-3.47h3.047V9.43c0-3.007 1.792-4.669 4.533-4.669 1.312 0 2.686.235 2.686.235v2.953H15.83c-1.491 0-1.956.925-1.956 1.874v2.25h3.328l-.532 3.47h-2.796v8.385C19.612 23.027 24 18.062 24 12.073z" /></svg><span class="social-sharing-icon-label" style="font-size:16px;color:inherit;">Facebook</span></a></li><li class="social-sharing-icon-li"><a class="social-sharing-icon social-sharing-icon-x" style="padding:5px 15px;margin:5px 5px;border-radius:50px;font-size:20px;color:#ffffff;background-color:#000000;" href="https://x.com/intent/tweet?url=https%3A%2F%2Flearnmodernjavascript.com%2Fsupercharge-your-react-apps-with-react-helmet-a-practical-guide-for-developers%2F&text=Supercharge+Your+React+Apps+with+%26%238216%3BReact-Helmet%26%238217%3B%3A+A+Practical+Guide+for+Developers" title="Share on X" target="_blank" rel="noopener noreferrer" data-platform="x"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="20" height="20" style="fill:#ffffff;" aria-hidden="true" focusable="false"><path d="M18.901 1.153h3.68l-8.04 9.19L24 22.846h-7.406l-5.8-7.584-6.638 7.584H.474l8.6-9.83L0 1.154h7.594l5.243 6.932ZM17.61 20.644h2.039L6.486 3.24H4.298Z" /></svg><span class="social-sharing-icon-label" style="font-size:16px;color:inherit;">Share on X</span></a></li><li class="social-sharing-icon-li"><a class="social-sharing-icon social-sharing-icon-linkedin" style="padding:5px 15px;margin:5px 5px;border-radius:50px;font-size:20px;color:#ffffff;background-color:#0966c2;" href="https://www.linkedin.com/sharing/share-offsite/?url=https%3A%2F%2Flearnmodernjavascript.com%2Fsupercharge-your-react-apps-with-react-helmet-a-practical-guide-for-developers%2F" title="LinkedIn" target="_blank" rel="noopener noreferrer" data-platform="linkedin"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="20" height="20" style="fill:#ffffff;" aria-hidden="true" focusable="false"><path d="M20.447 20.452h-3.554v-5.569c0-1.328-.027-3.037-1.852-3.037-1.853 0-2.136 1.445-2.136 2.939v5.667H9.351V9h3.414v1.561h.046c.477-.9 1.637-1.85 3.37-1.85 3.601 0 4.267 2.37 4.267 5.455v6.286zM5.337 7.433c-1.144 0-2.063-.926-2.063-2.065 0-1.138.92-2.063 2.063-2.063 1.14 0 2.064.925 2.064 2.063 0 1.139-.925 2.065-2.064 2.065zm1.782 13.019H3.555V9h3.564v11.452zM22.225 0H1.771C.792 0 0 .774 0 1.729v20.542C0 23.227.792 24 1.771 24h20.451C23.2 24 24 23.227 24 22.271V1.729C24 .774 23.2 0 22.222 0h.003z" /></svg><span class="social-sharing-icon-label" style="font-size:16px;color:inherit;">LinkedIn</span></a></li><li class="social-sharing-icon-li"><a class="social-sharing-icon social-sharing-icon-whatsapp" style="padding:5px 15px;margin:5px 5px;border-radius:50px;font-size:20px;color:#ffffff;background-color:#25D366;" href="https://api.whatsapp.com/send?text=Supercharge+Your+React+Apps+with+%26%238216%3BReact-Helmet%26%238217%3B%3A+A+Practical+Guide+for+Developers+https%3A%2F%2Flearnmodernjavascript.com%2Fsupercharge-your-react-apps-with-react-helmet-a-practical-guide-for-developers%2F" title="WhatsApp" target="_blank" rel="noopener noreferrer" data-platform="whatsapp"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="20" height="20" style="fill:#ffffff;" aria-hidden="true" focusable="false"><path d="M17.472 14.382c-.297-.149-1.758-.867-2.03-.967-.273-.099-.471-.148-.67.15-.197.297-.767.966-.94 1.164-.173.199-.347.223-.644.075-.297-.15-1.255-.463-2.39-1.475-.883-.788-1.48-1.761-1.653-2.059-.173-.297-.018-.458.13-.606.134-.133.298-.347.446-.52.149-.174.198-.298.298-.497.099-.198.05-.371-.025-.52-.075-.149-.669-1.612-.916-2.207-.242-.579-.487-.5-.669-.51-.173-.008-.371-.01-.57-.01-.198 0-.52.074-.792.372-.272.297-1.04 1.016-1.04 2.479 0 1.462 1.065 2.875 1.213 3.074.149.198 2.096 3.2 5.077 4.487.709.306 1.262.489 1.694.625.712.227 1.36.195 1.871.118.571-.085 1.758-.719 2.006-1.413.248-.694.248-1.289.173-1.413-.074-.124-.272-.198-.57-.347m-5.421 7.403h-.004a9.87 9.87 0 01-5.031-1.378l-.361-.214-3.741.982.998-3.648-.235-.374a9.86 9.86 0 01-1.51-5.26c.001-5.45 4.436-9.884 9.888-9.884 2.64 0 5.122 1.03 6.988 2.898a9.825 9.825 0 012.893 6.994c-.003 5.45-4.437 9.884-9.885 9.884m8.413-18.297A11.815 11.815 0 0012.05 0C5.495 0 .16 5.335.157 11.892c0 2.096.547 4.142 1.588 5.945L.057 24l6.305-1.654a11.882 11.882 0 005.683 1.448h.005c6.554 0 11.89-5.335 11.893-11.893a11.821 11.821 0 00-3.48-8.413z" /></svg><span class="social-sharing-icon-label" style="font-size:16px;color:inherit;">WhatsApp</span></a></li><li class="social-sharing-icon-li"><a class="social-sharing-icon social-sharing-icon-email" style="padding:5px 15px;margin:5px 5px;border-radius:50px;font-size:20px;color:#ffffff;background-color:#333333;" href="mailto:?subject=Supercharge+Your+React+Apps+with+%26%238216%3BReact-Helmet%26%238217%3B%3A+A+Practical+Guide+for+Developers&body=https%3A%2F%2Flearnmodernjavascript.com%2Fsupercharge-your-react-apps-with-react-helmet-a-practical-guide-for-developers%2F" title="Email" target="_blank" rel="noopener noreferrer" data-platform="email"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="20" height="20" style="fill:#ffffff;" aria-hidden="true" focusable="false"><path d="M20 4H4c-1.1 0-1.99.9-1.99 2L2 18c0 1.1.9 2 2 2h16c1.1 0 2-.9 2-2V6c0-1.1-.9-2-2-2zm-.4 4.25l-7.07 4.42c-.32.2-.74.2-1.06 0L4.4 8.25c-.25-.16-.4-.43-.4-.72 0-.67.73-1.07 1.3-.72L12 11l6.7-4.19c.57-.35 1.3.05 1.3.72 0 .29-.15.56-.4.72z" /></svg><span class="social-sharing-icon-label" style="font-size:16px;color:inherit;">Email</span></a></li><li class="social-sharing-icon-li"><a class="social-sharing-icon social-sharing-icon-copy-link" style="padding:5px 15px;margin:5px 5px;border-radius:50px;font-size:20px;color:#ffffff;background-color:#333333;" href="#copy-link" title="Copy Link" data-platform="copy-link"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="20" height="20" style="fill:#ffffff;" aria-hidden="true" focusable="false"><path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76 0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71 0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71 0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76 0 5-2.24 5-5s-2.24-5-5-5z" /></svg><span class="social-sharing-icon-label" style="font-size:16px;color:inherit;">Copy Link</span></a></li></ul><script> document.addEventListener("DOMContentLoaded", function() { var copyLinks = document.querySelectorAll("a[data-platform='copy-link']"); copyLinks.forEach(function(link) { if (link.hasAttribute("data-listener-added")) return; link.setAttribute("data-listener-added", "true"); link.addEventListener("click", function(e) { e.preventDefault(); var tempInput = document.createElement("input"); tempInput.value = window.location.href; document.body.appendChild(tempInput); tempInput.select(); document.execCommand("copy"); document.body.removeChild(tempInput); var originalText = this.querySelector(".social-sharing-icon-label")?.textContent || ""; var originalTitle = this.getAttribute("title"); var originalIcon = this.querySelector("svg").outerHTML; // Show success feedback this.setAttribute("title", "Copied!"); this.classList.add("copied"); if (this.querySelector(".social-sharing-icon-label")) { this.querySelector(".social-sharing-icon-label").textContent = "Copied!"; } else { this.querySelector("svg").outerHTML = '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="20" height="20" style="fill:#ffffff;" aria-hidden="true" focusable="false"><path d="M9 16.17L4.83 12l-1.42 1.41L9 19 21 7l-1.41-1.41L9 16.17z" /></svg>'; } var self = this; setTimeout(function() { self.setAttribute("title", originalTitle); self.classList.remove("copied"); if (self.querySelector(".social-sharing-icon-label")) { self.querySelector(".social-sharing-icon-label").textContent = originalText; } else { self.querySelector("svg").outerHTML = originalIcon; } }, 2000); }); }); }); </script></div></div></div> <div class="wp-block-group has-global-padding is-layout-constrained wp-block-group-is-layout-constrained" style="padding-top:var(--wp--preset--spacing--60);padding-bottom:var(--wp--preset--spacing--60)"><div class="taxonomy-post_tag is-style-post-terms-1 is-style-post-terms-1--2 wp-block-post-terms"><a href="https://learnmodernjavascript.com/tag/beginners/" rel="tag">Beginners</a><span class="wp-block-post-terms__separator"> </span><a href="https://learnmodernjavascript.com/tag/document-head/" rel="tag">document head</a><span class="wp-block-post-terms__separator"> </span><a href="https://learnmodernjavascript.com/tag/intermediate/" rel="tag">intermediate</a><span class="wp-block-post-terms__separator"> </span><a href="https://learnmodernjavascript.com/tag/javascript/" rel="tag">JavaScript</a><span class="wp-block-post-terms__separator"> </span><a href="https://learnmodernjavascript.com/tag/meta-tags/" rel="tag">meta tags</a><span class="wp-block-post-terms__separator"> </span><a href="https://learnmodernjavascript.com/tag/npm/" rel="tag">npm</a><span class="wp-block-post-terms__separator"> </span><a href="https://learnmodernjavascript.com/tag/open-graph/" rel="tag">Open Graph</a><span class="wp-block-post-terms__separator"> </span><a href="https://learnmodernjavascript.com/tag/react/" rel="tag">React</a><span class="wp-block-post-terms__separator"> </span><a href="https://learnmodernjavascript.com/tag/react-helmet/" rel="tag">React Helmet</a><span class="wp-block-post-terms__separator"> </span><a href="https://learnmodernjavascript.com/tag/seo/" rel="tag">SEO</a><span class="wp-block-post-terms__separator"> </span><a href="https://learnmodernjavascript.com/tag/server-side-rendering/" rel="tag">server-side rendering</a><span class="wp-block-post-terms__separator"> </span><a href="https://learnmodernjavascript.com/tag/tutorial/" rel="tag">Tutorial</a><span class="wp-block-post-terms__separator"> </span><a href="https://learnmodernjavascript.com/tag/web-development/" rel="tag">Web Development</a></div></div> <div class="wp-block-group alignwide is-layout-flow wp-block-group-is-layout-flow" style="margin-top:var(--wp--preset--spacing--60);margin-bottom:var(--wp--preset--spacing--60)"> <nav class="wp-block-group alignwide is-content-justification-space-between is-nowrap is-layout-flex wp-container-core-group-is-layout-878fe601 wp-block-group-is-layout-flex" aria-label="Post navigation" style="border-top-color:var(--wp--preset--color--accent-6);border-top-width:1px;padding-top:var(--wp--preset--spacing--40);padding-bottom:var(--wp--preset--spacing--40)"><div class="post-navigation-link-previous wp-block-post-navigation-link"><span class="wp-block-post-navigation-link__arrow-previous is-arrow-arrow" aria-hidden="true">←</span><a href="https://learnmodernjavascript.com/supercharge-your-react-apps-with-react-select-a-practical-guide-for-developers/" rel="prev">Supercharge Your React Apps with ‘React-Select’: A Practical Guide for Developers</a></div> <div class="post-navigation-link-next wp-block-post-navigation-link"><a href="https://learnmodernjavascript.com/supercharge-your-react-apps-with-react-lazy-load-image-component-a-practical-guide-for-developers/" rel="next">Supercharge Your React Apps with ‘React-Lazy-Load-Image-Component’: A Practical Guide for Developers</a><span class="wp-block-post-navigation-link__arrow-next is-arrow-arrow" aria-hidden="true">→</span></div></nav> </div> </div> <div class="wp-block-group alignwide has-global-padding is-layout-constrained wp-block-group-is-layout-constrained" style="padding-top:var(--wp--preset--spacing--60);padding-bottom:var(--wp--preset--spacing--60)"> <h2 class="wp-block-heading alignwide has-small-font-size" style="font-style:normal;font-weight:700;letter-spacing:1.4px;text-transform:uppercase">More posts</h2> <div class="wp-block-query alignwide is-layout-flow wp-block-query-is-layout-flow"><ul class="alignfull wp-block-post-template is-layout-flow wp-container-core-post-template-is-layout-b4d04ffe wp-block-post-template-is-layout-flow"><li class="wp-block-post post-4507 post type-post status-publish format-standard hentry category-javascript tag-beginner tag-canvas tag-css tag-dom-manipulation tag-drawing-app tag-event-handling tag-html tag-interactive tag-tutorial tag-typescript tag-web-development"> <div class="wp-block-group alignfull is-content-justification-space-between is-nowrap is-layout-flex wp-container-core-group-is-layout-cba70755 wp-block-group-is-layout-flex" style="border-bottom-color:var(--wp--preset--color--accent-6);border-bottom-width:1px;padding-top:var(--wp--preset--spacing--30);padding-bottom:var(--wp--preset--spacing--30)"><h3 class="wp-block-post-title has-large-font-size"><a href="https://learnmodernjavascript.com/typescript-tutorial-building-a-simple-interactive-drawing-application/" target="_self" >TypeScript Tutorial: Building a Simple Interactive Drawing Application</a></h3> <div class="has-text-align-right wp-block-post-date"><a href="https://learnmodernjavascript.com/typescript-tutorial-building-a-simple-interactive-drawing-application/"><time datetime="2026-03-20T21:51:29+00:00">March 20, 2026</time></a></div></div> </li><li class="wp-block-post post-4451 post type-post status-publish format-standard hentry category-javascript tag-beginners tag-css tag-form-validation tag-html tag-intermediate tag-javascript tag-tutorial tag-typescript tag-web-development"> <div class="wp-block-group alignfull is-content-justification-space-between is-nowrap is-layout-flex wp-container-core-group-is-layout-cba70755 wp-block-group-is-layout-flex" style="border-bottom-color:var(--wp--preset--color--accent-6);border-bottom-width:1px;padding-top:var(--wp--preset--spacing--30);padding-bottom:var(--wp--preset--spacing--30)"><h3 class="wp-block-post-title has-large-font-size"><a href="https://learnmodernjavascript.com/typescript-tutorial-building-a-simple-interactive-form-with-validation/" target="_self" >TypeScript Tutorial: Building a Simple Interactive Form with Validation</a></h3> <div class="has-text-align-right wp-block-post-date"><a href="https://learnmodernjavascript.com/typescript-tutorial-building-a-simple-interactive-form-with-validation/"><time datetime="2026-03-20T18:01:15+00:00">March 20, 2026</time></a></div></div> </li><li class="wp-block-post post-4445 post type-post status-publish format-standard hentry category-javascript tag-beginner tag-css tag-game-development tag-html tag-javascript tag-tic-tac-toe tag-tutorial tag-typescript tag-web-development"> <div class="wp-block-group alignfull is-content-justification-space-between is-nowrap is-layout-flex wp-container-core-group-is-layout-cba70755 wp-block-group-is-layout-flex" style="border-bottom-color:var(--wp--preset--color--accent-6);border-bottom-width:1px;padding-top:var(--wp--preset--spacing--30);padding-bottom:var(--wp--preset--spacing--30)"><h3 class="wp-block-post-title has-large-font-size"><a href="https://learnmodernjavascript.com/typescript-tutorial-building-a-simple-game-of-tic-tac-toe/" target="_self" >TypeScript Tutorial: Building a Simple Game of Tic-Tac-Toe</a></h3> <div class="has-text-align-right wp-block-post-date"><a href="https://learnmodernjavascript.com/typescript-tutorial-building-a-simple-game-of-tic-tac-toe/"><time datetime="2026-03-20T17:37:44+00:00">March 20, 2026</time></a></div></div> </li><li class="wp-block-post post-4443 post type-post status-publish format-standard hentry category-javascript tag-api tag-beginner tag-cli tag-currency-converter tag-node-js tag-tutorial tag-typescript tag-web-development"> <div class="wp-block-group alignfull is-content-justification-space-between is-nowrap is-layout-flex wp-container-core-group-is-layout-cba70755 wp-block-group-is-layout-flex" style="border-bottom-color:var(--wp--preset--color--accent-6);border-bottom-width:1px;padding-top:var(--wp--preset--spacing--30);padding-bottom:var(--wp--preset--spacing--30)"><h3 class="wp-block-post-title has-large-font-size"><a href="https://learnmodernjavascript.com/typescript-tutorial-building-a-simple-currency-converter/" target="_self" >TypeScript Tutorial: Building a Simple Currency Converter</a></h3> <div class="has-text-align-right wp-block-post-date"><a href="https://learnmodernjavascript.com/typescript-tutorial-building-a-simple-currency-converter/"><time datetime="2026-03-20T17:30:49+00:00">March 20, 2026</time></a></div></div> </li></ul></div> </div> </main> <footer class="wp-block-template-part"> <div class="wp-block-group has-global-padding is-layout-constrained wp-block-group-is-layout-constrained" style="padding-top:var(--wp--preset--spacing--60);padding-bottom:var(--wp--preset--spacing--50)"> <div class="wp-block-group alignwide is-layout-flow wp-block-group-is-layout-flow"><div class="is-default-size wp-block-site-logo"><a href="https://learnmodernjavascript.com/" class="custom-logo-link" rel="home"><img width="401" height="267" src="https://learnmodernjavascript.com/wp-content/uploads/2026/02/ChatGPT_Image_Feb_3__2026__04_44_02_PM-removebg-preview-edited-1.png" class="custom-logo" alt="LearnModernJavaScript" decoding="async" fetchpriority="high" srcset="https://learnmodernjavascript.com/wp-content/uploads/2026/02/ChatGPT_Image_Feb_3__2026__04_44_02_PM-removebg-preview-edited-1.png 401w, https://learnmodernjavascript.com/wp-content/uploads/2026/02/ChatGPT_Image_Feb_3__2026__04_44_02_PM-removebg-preview-edited-1-300x200.png 300w" sizes="(max-width: 401px) 100vw, 401px" /></a></div> <div class="wp-block-group alignfull is-content-justification-space-between is-layout-flex wp-container-core-group-is-layout-cf54d0a6 wp-block-group-is-layout-flex"> <div class="wp-block-columns is-layout-flex wp-container-core-columns-is-layout-794e3cfa wp-block-columns-is-layout-flex"> <div class="wp-block-column is-layout-flow wp-block-column-is-layout-flow" style="flex-basis:100%"><p class="wp-block-site-tagline">Learn JavaScript the Modern Way</p></div> <div class="wp-block-column is-layout-flow wp-block-column-is-layout-flow"> <div style="height:var(--wp--preset--spacing--40);width:0px" aria-hidden="true" class="wp-block-spacer"></div> </div> </div> </div> <div class="wp-block-group alignfull is-content-justification-space-between is-layout-flex wp-container-core-group-is-layout-2ab8c7fb wp-block-group-is-layout-flex"> <p class="has-small-font-size wp-block-paragraph">© 2026 • LearnModernJavascript</p> <p class="has-small-font-size wp-block-paragraph">Inquiries: <strong><a href="mailto:admin@codingeasypeasy.com">admin@learnmodernjavascript.com</a></strong></p> </div> </div> </div> </footer></div> <script type="speculationrules"> {"prefetch":[{"source":"document","where":{"and":[{"href_matches":"/*"},{"not":{"href_matches":["/wp-*.php","/wp-admin/*","/wp-content/uploads/*","/wp-content/*","/wp-content/plugins/*","/wp-content/themes/twentytwentyfive/*","/*\\?(.+)"]}},{"not":{"selector_matches":"a[rel~=\"nofollow\"]"}},{"not":{"selector_matches":".no-prefetch, .no-prefetch a"}}]},"eagerness":"conservative"}]} </script> <div class="wp-dark-mode-floating-switch wp-dark-mode-ignore wp-dark-mode-animation wp-dark-mode-animation-bounce " style="right: 10px; bottom: 10px;"> <!-- call to action --> <div class="wp-dark-mode-switch wp-dark-mode-ignore " tabindex="0" role="switch" aria-label="Dark Mode Toggle" aria-checked="false" data-style="1" data-size="1" data-text-light="" data-text-dark="" data-icon-light="" data-icon-dark=""></div></div><script data-wp-router-options="{"loadOnClientNavigation":true}" fetchpriority="low" id="@wordpress/block-library/navigation/view-js-module" src="https://learnmodernjavascript.com/wp-includes/js/dist/script-modules/block-library/navigation/view.min.js?ver=96a846e1d7b789c39ab9" type="module"></script> <!-- Koko Analytics v2.4.0 - https://www.kokoanalytics.com/ --> <script> (()=>{var e=window.koko_analytics,c=["utm_source","utm_medium","utm_campaign"];function d(){let t={},a=new URLSearchParams(window.location.search),s=new URLSearchParams(window.location.hash.substring(1));return c.forEach(i=>{let n=a.get(i)||s.get(i);n&&(t[i]=n)}),t}e.trackPageview=function(t,a){if(/bot|crawl|spider|seo|lighthouse|facebookexternalhit|preview|prerender/i.test(navigator.userAgent)||window._phantom||window.__nightmare||window.navigator.webdriver||window.Cypress){console.debug("Koko Analytics: Ignoring call to trackPageview because user agent is a bot or this is a headless browser.");return}navigator.sendBeacon(e.url,new URLSearchParams({action:"koko_analytics_collect",pa:t,po:a,r:document.referrer.indexOf(e.site_url)==0?"":document.referrer,m:e.use_cookie?"c":e.method[0],...d()}))};function o(){e.trackPageview(e.path,e.post_id)}function r(){e.autotracked||(o(),e.autotracked=!0)}document.visibilityState==="hidden"||document.visibilityState==="prerender"?document.addEventListener("visibilitychange",()=>{document.visibilityState==="visible"&&r()}):r();window.addEventListener("pageshow",t=>{t.persisted&&o()});})(); </script> <script>document.addEventListener("DOMContentLoaded", function() { // ---------- CONFIG ---------- const MONETAG_URL = "https://omg10.com/4/10704559"; const STORAGE_KEY = "monetagLastShown"; const COOLDOWN = 24*60*60*1000; // 24 hours // ---------- CREATE MODAL HTML ---------- const modalHTML = ` <div id="monetagModal" style=" position:fixed; top:0; left:0; width:100%; height:100%; background:rgba(0,0,0,0.7); display:flex; align-items:center; justify-content:center; z-index:9999; visibility:hidden; opacity:0; transition: opacity 0.3s ease; "> <div style=" background:#fff; padding:25px; border-radius:10px; max-width:400px; text-align:center; box-shadow:0 4px 15px rgba(0,0,0,0.3); "> <h2>Welcome! 👋</h2> <p>Thanks for visiting! Before you continue, click the button below to unlock exclusive content and surprises just for you.</p> <button class="monetagBtn" style=" padding:10px 20px; background:#dc3545; color:#fff; border:none; border-radius:5px; cursor:pointer; margin-top:15px; ">Not Now</button> <button class="monetagBtn" style=" padding:10px 20px; background:#ff5722; color:#fff; border:none; border-radius:5px; cursor:pointer; margin-top:15px; ">Continue</button> </div> </div> `; document.body.insertAdjacentHTML("beforeend", modalHTML); // ---------- GET ELEMENTS ---------- const modal = document.getElementById("monetagModal"); const buttons = document.querySelectorAll(".monetagBtn"); // ---------- SHOW MODAL ON PAGE LOAD ---------- window.addEventListener("load", function(){ modal.style.visibility = "visible"; modal.style.opacity = "1"; }); // ---------- CHECK 24H COOLDOWN ---------- function canShow() { const last = localStorage.getItem(STORAGE_KEY); return !last || (Date.now() - parseInt(last)) > COOLDOWN; } // ---------- TRIGGER MONETAG ---------- buttons.forEach(btn => { btn.addEventListener("click", function(){ if(canShow()){ localStorage.setItem(STORAGE_KEY, Date.now()); window.open(MONETAG_URL,"_blank"); } // hide modal after click modal.style.opacity = "0"; setTimeout(()=>{ modal.style.visibility="hidden"; },300); }); }); });</script><script id="prismatic-prism-js" src="https://learnmodernjavascript.com/wp-content/plugins/prismatic/lib/prism/js/prism-core.js?ver=3.7.5"></script> <script id="prismatic-prism-toolbar-js" src="https://learnmodernjavascript.com/wp-content/plugins/prismatic/lib/prism/js/plugin-toolbar.js?ver=3.7.5"></script> <script id="prismatic-prism-line-highlight-js" src="https://learnmodernjavascript.com/wp-content/plugins/prismatic/lib/prism/js/plugin-line-highlight.js?ver=3.7.5"></script> <script id="prismatic-prism-line-numbers-js" src="https://learnmodernjavascript.com/wp-content/plugins/prismatic/lib/prism/js/plugin-line-numbers.js?ver=3.7.5"></script> <script id="prismatic-copy-clipboard-js" src="https://learnmodernjavascript.com/wp-content/plugins/prismatic/lib/prism/js/plugin-copy-clipboard.js?ver=3.7.5"></script> <script id="prismatic-command-line-js" src="https://learnmodernjavascript.com/wp-content/plugins/prismatic/lib/prism/js/plugin-command-line.js?ver=3.7.5"></script> <script id="prismatic-prism-bash-js" src="https://learnmodernjavascript.com/wp-content/plugins/prismatic/lib/prism/js/lang-bash.js?ver=3.7.5"></script> <script id="prismatic-prism-jsx-js" src="https://learnmodernjavascript.com/wp-content/plugins/prismatic/lib/prism/js/lang-jsx.js?ver=3.7.5"></script> <script id="zoom-social-icons-widget-frontend-js" src="https://learnmodernjavascript.com/wp-content/plugins/social-icons-widget-by-wpzoom/assets/js/social-icons-widget-frontend.js?ver=1500579482"></script> <script id="wp-emoji-settings" type="application/json"> {"baseUrl":"https://s.w.org/images/core/emoji/17.0.2/72x72/","ext":".png","svgUrl":"https://s.w.org/images/core/emoji/17.0.2/svg/","svgExt":".svg","source":{"concatemoji":"https://learnmodernjavascript.com/wp-includes/js/wp-emoji-release.min.js?ver=7.0"}} </script> <script type="module"> /*! This file is auto-generated */ const a=JSON.parse(document.getElementById("wp-emoji-settings").textContent),o=(window._wpemojiSettings=a,"wpEmojiSettingsSupports"),s=["flag","emoji"];function i(e){try{var t={supportTests:e,timestamp:(new Date).valueOf()};sessionStorage.setItem(o,JSON.stringify(t))}catch(e){}}function c(e,t,n){e.clearRect(0,0,e.canvas.width,e.canvas.height),e.fillText(t,0,0);t=new Uint32Array(e.getImageData(0,0,e.canvas.width,e.canvas.height).data);e.clearRect(0,0,e.canvas.width,e.canvas.height),e.fillText(n,0,0);const a=new Uint32Array(e.getImageData(0,0,e.canvas.width,e.canvas.height).data);return t.every((e,t)=>e===a[t])}function p(e,t){e.clearRect(0,0,e.canvas.width,e.canvas.height),e.fillText(t,0,0);var n=e.getImageData(16,16,1,1);for(let e=0;e<n.data.length;e++)if(0!==n.data[e])return!1;return!0}function u(e,t,n,a){switch(t){case"flag":return n(e,"\ud83c\udff3\ufe0f\u200d\u26a7\ufe0f","\ud83c\udff3\ufe0f\u200b\u26a7\ufe0f")?!1:!n(e,"\ud83c\udde8\ud83c\uddf6","\ud83c\udde8\u200b\ud83c\uddf6")&&!n(e,"\ud83c\udff4\udb40\udc67\udb40\udc62\udb40\udc65\udb40\udc6e\udb40\udc67\udb40\udc7f","\ud83c\udff4\u200b\udb40\udc67\u200b\udb40\udc62\u200b\udb40\udc65\u200b\udb40\udc6e\u200b\udb40\udc67\u200b\udb40\udc7f");case"emoji":return!a(e,"\ud83e\u1fac8")}return!1}function f(e,t,n,a){let r;const o=(r="undefined"!=typeof WorkerGlobalScope&&self instanceof WorkerGlobalScope?new OffscreenCanvas(300,150):document.createElement("canvas")).getContext("2d",{willReadFrequently:!0}),s=(o.textBaseline="top",o.font="600 32px Arial",{});return e.forEach(e=>{s[e]=t(o,e,n,a)}),s}function r(e){var t=document.createElement("script");t.src=e,t.defer=!0,document.head.appendChild(t)}a.supports={everything:!0,everythingExceptFlag:!0},new Promise(t=>{let n=function(){try{var e=JSON.parse(sessionStorage.getItem(o));if("object"==typeof e&&"number"==typeof e.timestamp&&(new Date).valueOf()<e.timestamp+604800&&"object"==typeof e.supportTests)return e.supportTests}catch(e){}return null}();if(!n){if("undefined"!=typeof Worker&&"undefined"!=typeof OffscreenCanvas&&"undefined"!=typeof URL&&URL.createObjectURL&&"undefined"!=typeof Blob)try{var e="postMessage("+f.toString()+"("+[JSON.stringify(s),u.toString(),c.toString(),p.toString()].join(",")+"));",a=new Blob([e],{type:"text/javascript"});const r=new Worker(URL.createObjectURL(a),{name:"wpTestEmojiSupports"});return void(r.onmessage=e=>{i(n=e.data),r.terminate(),t(n)})}catch(e){}i(n=f(s,u,c,p))}t(n)}).then(e=>{for(const n in e)a.supports[n]=e[n],a.supports.everything=a.supports.everything&&a.supports[n],"flag"!==n&&(a.supports.everythingExceptFlag=a.supports.everythingExceptFlag&&a.supports[n]);var t;a.supports.everythingExceptFlag=a.supports.everythingExceptFlag&&!a.supports.flag,a.supports.everything||((t=a.source||{}).concatemoji?r(t.concatemoji):t.wpemoji&&t.twemoji&&(r(t.twemoji),r(t.wpemoji)))}); //# sourceURL=https://learnmodernjavascript.com/wp-includes/js/wp-emoji-loader.min.js </script> <script> (function() { function applyScrollbarStyles() { if (!document.documentElement.hasAttribute('data-wp-dark-mode-active')) { document.documentElement.style.removeProperty('scrollbar-color'); return; } document.documentElement.style.setProperty('scrollbar-color', '#2E334D #1D2033', 'important'); // Find and remove dark mode engine scrollbar styles. var styles = document.querySelectorAll('style'); styles.forEach(function(style) { if (style.id === 'wp-dark-mode-scrollbar-custom') return; if (style.textContent && style.textContent.indexOf('::-webkit-scrollbar') !== -1 && style.textContent.indexOf('#1D2033') === -1) { style.textContent = style.textContent.replace(/::-webkit-scrollbar[^}]*\{[^}]*\}/g, ''); style.textContent = style.textContent.replace(/::-webkit-scrollbar-track[^}]*\{[^}]*\}/g, ''); style.textContent = style.textContent.replace(/::-webkit-scrollbar-thumb[^{]*\{[^}]*\}/g, ''); style.textContent = style.textContent.replace(/::-webkit-scrollbar-corner[^}]*\{[^}]*\}/g, ''); } }); // Inject our styles. var existing = document.getElementById('wp-dark-mode-scrollbar-custom'); if (!existing) { var customStyle = document.createElement('style'); customStyle.id = 'wp-dark-mode-scrollbar-custom'; customStyle.textContent = '::-webkit-scrollbar { width: 12px !important; height: 12px !important; background: #1D2033 !important; }' + '::-webkit-scrollbar-track { background: #1D2033 !important; }' + '::-webkit-scrollbar-thumb { background: #2E334D !important; border-radius: 6px; }' + '::-webkit-scrollbar-thumb:hover { filter: brightness(1.2); }' + '::-webkit-scrollbar-corner { background: #1D2033 !important; }'; document.body.appendChild(customStyle); } } // Listen for dark mode changes. document.addEventListener('wp_dark_mode', function(e) { setTimeout(applyScrollbarStyles, 100); setTimeout(applyScrollbarStyles, 500); setTimeout(applyScrollbarStyles, 1000); }); // Observe attribute changes. var observer = new MutationObserver(function(mutations) { mutations.forEach(function(mutation) { if (mutation.attributeName === 'data-wp-dark-mode-active') { var existing = document.getElementById('wp-dark-mode-scrollbar-custom'); if (existing && !document.documentElement.hasAttribute('data-wp-dark-mode-active')) { existing.remove(); } setTimeout(applyScrollbarStyles, 100); setTimeout(applyScrollbarStyles, 500); } }); }); observer.observe(document.documentElement, { attributes: true }); // Initial apply. setTimeout(applyScrollbarStyles, 100); setTimeout(applyScrollbarStyles, 500); setTimeout(applyScrollbarStyles, 1000); })(); </script> </body> </html>