<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Andreas Riedmüller</title>
    <description>The latest articles on Forem by Andreas Riedmüller (@receter).</description>
    <link>https://forem.com/receter</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F147018%2F45cc0af4-77b0-4229-b4c1-e935dc0a68fc.jpeg</url>
      <title>Forem: Andreas Riedmüller</title>
      <link>https://forem.com/receter</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/receter"/>
    <language>en</language>
    <item>
      <title>npm Classic Tokens Are Gone: Two Low-Maintenance Ways to Keep Publishing</title>
      <dc:creator>Andreas Riedmüller</dc:creator>
      <pubDate>Tue, 20 Jan 2026 09:49:57 +0000</pubDate>
      <link>https://forem.com/receter/npm-classic-tokens-are-gone-two-low-maintenance-ways-to-keep-publishing-4idh</link>
      <guid>https://forem.com/receter/npm-classic-tokens-are-gone-two-low-maintenance-ways-to-keep-publishing-4idh</guid>
      <description>&lt;p&gt;npm recently announced that classic npm tokens are being deprecated and revoked. Everyone has to migrate to granular tokens, which come with an expiration date (and for publish/write use cases, that effectively means regular rotation).&lt;/p&gt;

&lt;p&gt;And, strangely, in the UI there isn’t even an option to &lt;em&gt;renew&lt;/em&gt; a token. You basically have to &lt;em&gt;create a new token&lt;/em&gt; (and delete the old one) every time.&lt;/p&gt;

&lt;p&gt;I maintain a few packages on GitHub, and my first thought was: “Do I really have to do this every 90 days just to keep publishing working?” That would be a little nightmare.&lt;/p&gt;

&lt;p&gt;But after reading the announcement and docs, I found there are &lt;strong&gt;two major things&lt;/strong&gt; you can do to make your life easier.&lt;/p&gt;

&lt;h2&gt;
  
  
  1) Use the CLI to manage tokens
&lt;/h2&gt;

&lt;p&gt;There’s a &lt;a href="https://docs.npmjs.com/cli/v11/commands/npm-token" rel="noopener noreferrer"&gt;CLI for managing tokens&lt;/a&gt;, so you can set up a script to rotate them automatically — something like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;npm run renew-token&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This way, you don’t have to click around the npm website every time.&lt;/p&gt;

&lt;h2&gt;
  
  
  2) Use OIDC (Trusted Publishing) from GitHub/GitLab
&lt;/h2&gt;

&lt;p&gt;If your workflow runs on GitHub Actions or GitLab CI/CD, you can use &lt;a href="https://docs.npmjs.com/trusted-publishers#supported-cicd-providers" rel="noopener noreferrer"&gt;OpenID Connect (OIDC)&lt;/a&gt; for an even more secure way to authenticate when your workflow publishes a package.&lt;/p&gt;

&lt;p&gt;This is zero maintenance once it’s set up: you &lt;strong&gt;don’t store a long-lived token at all&lt;/strong&gt;. Instead, you link your package to an official repository + workflow file, and npm will accept the publish if it comes from that trusted source. &lt;/p&gt;




&lt;p&gt;Now I’m happy again — and my setup is even simpler and more secure than it was before :)&lt;/p&gt;

&lt;p&gt;I hope this helped. Have a great day!&lt;/p&gt;

</description>
      <category>npm</category>
      <category>javascript</category>
      <category>devops</category>
    </item>
    <item>
      <title>Create Modal Dialogs in React 🍭</title>
      <dc:creator>Andreas Riedmüller</dc:creator>
      <pubDate>Fri, 16 Jan 2026 14:04:37 +0000</pubDate>
      <link>https://forem.com/receter/create-modal-dialogs-in-react-2ioj</link>
      <guid>https://forem.com/receter/create-modal-dialogs-in-react-2ioj</guid>
      <description>&lt;p&gt;Most apps use modal dialogs (aka &lt;em&gt;modals&lt;/em&gt;), and implementing a simple one is not &lt;em&gt;that&lt;/em&gt; hard: a div with some content, a bit of CSS for the backdrop and positioning, and voilà, you have a modal. But as your app grows, so do the requirements for your modals. Sooner or later, you may find yourself refactoring and debugging a surprising amount of code that is related to modals. At least that’s what happened to me.&lt;/p&gt;

&lt;p&gt;Accessibility, keyboard navigation, focus trapping, modal stacking, you name it.&lt;/p&gt;

&lt;p&gt;In this guide, I’ll walk you through a concise yet comprehensive modal dialog implementation in React. It’s the result of what I’ve learned about modals in React over the past few years. There are libraries for modals out there, but if you want an implementation you fully own and deeply understand, this guide is for you. We use this architecture in production for the customer dashboard at Userbrain.&lt;/p&gt;

&lt;p&gt;I’ve split this article into three parts. First, we’ll build the foundation of the modal framework. Next, we’ll add essential features for usability and accessibility. Finally, we’ll explore more advanced use cases and how to make the most of the system.&lt;/p&gt;

&lt;p&gt;What you will learn:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Part I&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;How to use React Portals to render modals and why.&lt;/li&gt;
&lt;li&gt;How to manage multiple modal dialogs that can be open simultaneously.&lt;/li&gt;
&lt;li&gt;How to style and control modal stacking visually&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Part II&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;How to trap focus inside a modal.&lt;/li&gt;
&lt;li&gt;How to close modals via the Escape key and by clicking outside.&lt;/li&gt;
&lt;li&gt;What you need to consider to meet modern accessibility guidelines.&lt;/li&gt;
&lt;li&gt;Learn more about the HTML &lt;code&gt;&amp;lt;dialog&amp;gt;&lt;/code&gt; element&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Part III&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Create different kinds of modals&lt;/li&gt;
&lt;li&gt;Advanced styling and transitions&lt;/li&gt;
&lt;li&gt;How to manage global modals&lt;/li&gt;
&lt;li&gt;How to control modals with routes&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Let’s start with the end in mind
&lt;/h2&gt;

&lt;p&gt;We’re going to build a React component that can render a modal anywhere in your app. Its &lt;em&gt;open&lt;/em&gt; state will be controlled by the parent component.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Modal&lt;/span&gt; &lt;span class="na"&gt;isOpen&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;isModalOpen&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  Hello, Modal!
&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;Modal&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A &lt;code&gt;Modal&lt;/code&gt; component can also be rendered &lt;em&gt;inside&lt;/em&gt; another &lt;code&gt;Modal&lt;/code&gt;, which leads to a hierarchical structure of modals.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Modal&lt;/span&gt; &lt;span class="na"&gt;isOpen&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;isModalOpen&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  Hello, Modal!
  &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Modal&lt;/span&gt; &lt;span class="na"&gt;isOpen&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;isNestedModalOpen&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    This is a nested modal.
  &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;Modal&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;Modal&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A modal dialog, by definition, blocks interaction with the rest of the application.&lt;/p&gt;

&lt;p&gt;Because multiple modals can be &lt;em&gt;open&lt;/em&gt; at the same time, we also need to determine which one is currently &lt;em&gt;active&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;In the following example, two sibling modals and one nested modal are rendered:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Modal&lt;/span&gt; &lt;span class="na"&gt;isOpen&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;isModalOneOpen&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  This is Modal One.
&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;Modal&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Modal&lt;/span&gt; &lt;span class="na"&gt;isOpen&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;isModalTwoOpen&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  This is Modal Two.
  &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Modal&lt;/span&gt; &lt;span class="na"&gt;isOpen&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;isConfirmModalOpen&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    Are your sure you want to close Modal Two?
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt; &lt;span class="na"&gt;onClick&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;handleClickYes&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Yes, close!&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt; &lt;span class="na"&gt;onClick&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;handleClickNevermind&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Nevermind&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;Modal&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;Modal&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let’s think about this example for a second. If all &lt;code&gt;isOpen&lt;/code&gt; props are &lt;em&gt;true&lt;/em&gt;, which modal should be &lt;em&gt;active&lt;/em&gt;?&lt;/p&gt;

&lt;p&gt;For &lt;strong&gt;Modal Two&lt;/strong&gt; and its nested modal, the answer is obvious: the &lt;strong&gt;Confirm Modal&lt;/strong&gt; must be &lt;em&gt;active&lt;/em&gt;, not its parent, &lt;strong&gt;Modal Two&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;But &lt;strong&gt;Modal One&lt;/strong&gt; could also be the &lt;em&gt;active&lt;/em&gt; modal in this example.&lt;/p&gt;

&lt;p&gt;We could use something like the order of appearance in JSX to determine the active modal, but that’s neither intuitive nor easy to implement in React.&lt;/p&gt;

&lt;p&gt;A more intuitive approach, in my opinion, is to treat the most recently opened modal as the &lt;em&gt;active&lt;/em&gt; one. This also aligns with how the HTML &lt;code&gt;&amp;lt;dialog&amp;gt;&lt;/code&gt; element behaves and is the strategy we use.&lt;/p&gt;

&lt;p&gt;Now that you have a general idea of what we are going to implement, let’s start writing some code.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. The portal
&lt;/h2&gt;

&lt;p&gt;Portals are a &lt;a href="https://react.dev/reference/react-dom/createPortal" rel="noopener noreferrer"&gt;feature of React&lt;/a&gt; that allows you to render JSX into a specific DOM node that can be located anywhere in your document.&lt;/p&gt;

&lt;p&gt;We will use Portals to render all modals into a "modal container" node outside the main app tree. By doing so, we make sure our modals aren’t affected by parent styles and we can more easily use features like &lt;em&gt;inert&lt;/em&gt; to disable background interaction for better accessibility. &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;If you want to follow along, start with a fresh TypeScript React project using &lt;code&gt;npm create vite@latest&lt;/code&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;First, create a ref to a DOM node where all modals will be rendered to:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="c1"&gt;// App.tsx&lt;/span&gt;
&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;App&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;refModalContainer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useRef&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;HTMLDivElement&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&amp;gt;&lt;/span&gt;
      &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="cm"&gt;/* … */&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt; &lt;span class="na"&gt;ref&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;refModalContainer&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;Keep in mind that the location of this node in the DOM influences which CSS rules, variable values, and other DOM-dependent behaviors apply to your modals.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;You can also use a ref to any other DOM node, such as &lt;code&gt;document.body&lt;/code&gt;. I intentionally use a DOM node inside the JSX tree because it requires a bit of extra work, and I want to demonstrate how to do that.&lt;/p&gt;

&lt;p&gt;Every modal needs to know about this DOM node, so let’s create a context that provides this information:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// context.ts&lt;/span&gt;
&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;ModalContextType&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;refModalContainer&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;RefObject&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;HTMLElement&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;ModalContext&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;createContext&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;ModalContextType&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And a &lt;code&gt;ModalProvider&lt;/code&gt; component that is responsible for providing this context:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="c1"&gt;// ModalProvider.tsx&lt;/span&gt;
&lt;span class="nx"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;ModalProviderProps&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;children&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ReactNode&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;refModalContainer&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;RefObject&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;HTMLDivElement&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;ModalProvider&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;children&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;refModalContainer&lt;/span&gt; &lt;span class="p"&gt;}:&lt;/span&gt; &lt;span class="nx"&gt;ModalProviderProps&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;modalContextValue&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;refModalContainer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;

  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;ModalContext&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Provider&lt;/span&gt; &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;modalContextValue&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;children&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;ModalContext&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Provider&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To make this context easy to consume, we create a &lt;code&gt;useModalContext&lt;/code&gt;  hook. It throws an error if used outside of a &lt;code&gt;ModalProvider&lt;/code&gt;. This is especially helpful when working with TypeScript, as it guarantees that the context exists when the hook is used.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// useModalContext.ts&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;useModalContext&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;modalContext&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useContext&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ModalContext&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;modalContext&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;useModalContext must be used within a ModalProvider.&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;modalContext&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then wrap the entire app in a &lt;code&gt;ModalProvider&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="c1"&gt;// App.tsx&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;refModalContainer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useRef&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;HTMLDivElement&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;ModalProvider&lt;/span&gt; &lt;span class="na"&gt;refModalContainer&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;refModalContainer&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="cm"&gt;/* … */&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;ModalProvider&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt; &lt;span class="na"&gt;ref&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;refModalContainer&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next, we create a component named &lt;code&gt;ModalPortal&lt;/code&gt; that simply renders its children into the modal container:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="c1"&gt;// ModalPortal.tsx&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;ModalPortal&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="nx"&gt;children&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;children&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ReactNode&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;refModalContainer&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useContext&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ModalContext&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;refModalContainer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;current&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;createPortal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="nx"&gt;children&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="nx"&gt;refModalContainer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;current&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can now try using &lt;code&gt;&amp;lt;ModalPortal&amp;gt;&lt;/code&gt;, and its children should be rendered into the modal container.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="c1"&gt;// App.tsx&lt;/span&gt;
&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;ModalProvider&lt;/span&gt; &lt;span class="na"&gt;refModalContainer&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;refModalContainer&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;ModalPortal&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    Hello, Modal Portal!
  &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;ModalPortal&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  /* … */
&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;ModalProvider&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;However, there is a catch: The modal container &lt;code&gt;div&lt;/code&gt; is only added to the DOM after React has completed rendering, so &lt;code&gt;refModalContainer.current&lt;/code&gt; is &lt;code&gt;null&lt;/code&gt; during the first render.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"Hello, Modal Portal!" will be rendered into the modal container as soon as you trigger a second render. If you still have the default Vite code in &lt;code&gt;App()&lt;/code&gt;, you can click the "count is …" button to trigger another render.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;You would not run into this problem if you used an already existing element, such as &lt;code&gt;document.body&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;We will fix this issue by adding a mechanism that automatically re-renders the portal if it was not created:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight diff"&gt;&lt;code&gt;// ModalPortal.tsx
&lt;span class="gi"&gt;+  const [, forceUpdate] = useReducer((x) =&amp;gt; x + 1, 0);
&lt;/span&gt;   /* … */
&lt;span class="gi"&gt;+  const refIsPortalCreated = useRef(false);
+  useEffect(() =&amp;gt; {
+    // This effect will run once for any given ref
+    if (refIsPortalCreated.current === false) {
+      forceUpdate();
+    }
+  }, [refModalContainer]);
&lt;/span&gt;&lt;span class="err"&gt;
&lt;/span&gt;  if (refModalContainer.current !== null) {
&lt;span class="gi"&gt;+    refIsPortalCreated.current = true;
&lt;/span&gt;    return createPortal(/* … */);
  } else {
&lt;span class="gi"&gt;+    refIsPortalCreated.current = false;
&lt;/span&gt;    return null;
  }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the render function, we record whether it was possible to create the portal in &lt;code&gt;refIsPortalCreated&lt;/code&gt;. The effect then runs afterward and calls &lt;code&gt;forceUpdate&lt;/code&gt; if that was not the case.&lt;/p&gt;

&lt;p&gt;A neat trick to create a function that forces a re-render is using &lt;code&gt;useReducer&lt;/code&gt;. I found this &lt;a href="https://stackoverflow.com/questions/46240647/how-to-force-a-functional-react-component-to-render/53837442#53837442" rel="noopener noreferrer"&gt;on Stack Overflow&lt;/a&gt; some time ago.&lt;/p&gt;

&lt;p&gt;Ok, first challenge completed!&lt;/p&gt;

&lt;h2&gt;
  
  
  🫀The heart of the system
&lt;/h2&gt;

&lt;p&gt;We have already created a &lt;code&gt;ModalProvider&lt;/code&gt; and a context. Now we extend both to provide everything necessary to build the &lt;code&gt;&amp;lt;Modal&amp;gt;&lt;/code&gt; component in the next step.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;ModalProvider&lt;/code&gt; will keep track of all modals and determines the stacking order and which modal is currently &lt;em&gt;active&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;To achieve this, we’ll store information about all mounted modals in a tree like structure. The stacking order can then be determined by flattening this tree.&lt;/p&gt;

&lt;p&gt;When a modal becomes &lt;em&gt;active&lt;/em&gt;, all of its nodes (the modal itself and its descendants) are moved to the end of their respective subtrees, ensuring the active branch is on top of the stack.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The modal on the bottom of the tree, will be on top of the stack.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;For example, when modal "A2a" becomes &lt;em&gt;active&lt;/em&gt;…&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;App              Z
├─ A             1
│  ├─ A1         2
│  │  └─ A1a     3
│  ├─ A2         4
│  │  └─ A2a     5 (becomes active)
│  └─ A3         6
│     └─ A3a     7
├─ B             8
│  ├─ B1         9
│  │  └─ B1a     10
│  └─ B2         11
│     └─ B2a     12
├─ C             13
└─ D*            14 (is active)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;… the tree is reordered so that the &lt;em&gt;active&lt;/em&gt; modal moves to the end of the flattened sequence:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;App              Z
├─ B             1
│  ├─ B1         2
│  │  └─ B1a     3
│  └─ B2         4
│     └─ B2a     5
├─ C             6
├─ D             7
└▼ A             8
   ├─ A1         9
   │  └─ A1a     10
   ├─ A3         11
   │  └─ A3a     12
   └▼ A2         13
      └▼ A2a*    14 (is active)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Later, when the &lt;em&gt;active&lt;/em&gt; modal is closed, we walk upwards and select the the next &lt;em&gt;open&lt;/em&gt; modal in the tree to become the &lt;em&gt;active&lt;/em&gt; modal:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;App              Z
├─ B             1
│  ├─ B1         2
│  │  └─ B1a     3
│  └─ B2         4
│     └─ B2a     5
├─ C             6
├─ D             7
└─ A             8
   ├─ A1         9
   │  └─ A1a     10
   ├─ A3         11
   │  └─ A3a     12
   └─ A2*        13 (is active)
      └─ A2a     14 (was closed)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This example may be more complex than typical app modals, but it illustrates how we manage focus, and stacking order for hierarchical modals.&lt;/p&gt;

&lt;p&gt;One thing to keep in mind when looking at this tree is that it shows all &lt;em&gt;mounted&lt;/em&gt; &lt;code&gt;&amp;lt;Modal&amp;gt;&lt;/code&gt; components and the &lt;code&gt;&amp;lt;Modal&amp;gt;&lt;/code&gt; component will only render its content when &lt;em&gt;open&lt;/em&gt;. This means that &lt;code&gt;&amp;lt;Modal&amp;gt;&lt;/code&gt; will not have children when not &lt;em&gt;open&lt;/em&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  The modal tree
&lt;/h3&gt;

&lt;p&gt;Calling it a &lt;em&gt;tree&lt;/em&gt; is probably not the right term, because it does not have a root. It’s an array of modal nodes, each of which can have descendants. If I’m not mistaken, this is actually called a &lt;em&gt;forest&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;For each modal we will store two pieces of information:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A unique id&lt;/li&gt;
&lt;li&gt;If the modal is &lt;em&gt;open&lt;/em&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And to manage this tree, we will need utility functions to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Add a node&lt;/li&gt;
&lt;li&gt;Remove a node&lt;/li&gt;
&lt;li&gt;Update a node&lt;/li&gt;
&lt;li&gt;Get a flat list of all nodes&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;When updating a node, we check whether it changed to &lt;code&gt;open&lt;/code&gt;, and if so, we move the node and its ancestors to the end.&lt;/p&gt;

&lt;p&gt;We start by creating a new file, &lt;code&gt;modalTree.ts&lt;/code&gt;, where we define the data structure and implement the utility functions to work with the tree—uh, forest.&lt;/p&gt;

&lt;p&gt;Damn it, I’ll just call it a tree.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// modalTree.ts&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;ModalTreeData&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;isOpen&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;boolean&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;ModalTreeNode&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ModalTreeData&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;children&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ModalTreeNode&lt;/span&gt;&lt;span class="p"&gt;[];&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="cm"&gt;/**
 * Inserts a new modal or updates an existing modal in the forest.
 * If parentId is null, adds/updates the modal as a root node.
 * If parentId is provided, adds/updates the modal as a child of the parent.
 * Also moves the node (and ancestors) to the end if it changes to open state
 * Returns a new forest with the changes applied (immutable).
 */&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;upsertModalNode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nx"&gt;modalNodes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ModalTreeNode&lt;/span&gt;&lt;span class="p"&gt;[],&lt;/span&gt;
  &lt;span class="nx"&gt;modalData&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ModalTreeData&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;parentId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nx"&gt;ModalTreeNode&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="cm"&gt;/* … */&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="cm"&gt;/**
 * Removes a modal from the forest by its ID.
 * If the modal has children, they are also removed (cascading delete).
 * Returns a new forest with the modal removed (immutable).
 */&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;removeModalNode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nx"&gt;modalNodes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ModalTreeNode&lt;/span&gt;&lt;span class="p"&gt;[],&lt;/span&gt;
  &lt;span class="nx"&gt;modalId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nx"&gt;ModalTreeNode&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="cm"&gt;/* … */&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="cm"&gt;/**
 * Flattens the forest into a single array of ModalTreeData in depth-first order.
 * For iterating over all modals and determining stack order.
 */&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;flattenModalNodes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nx"&gt;modalNodes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ModalTreeNode&lt;/span&gt;&lt;span class="p"&gt;[],&lt;/span&gt;
&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nx"&gt;ModalTreeData&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="cm"&gt;/* … */&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;Manipulating trees is not part of this article, so I’ll spare you the details of the utility functions here. I’ve moved them to a gist where you can copy the code if needed: &lt;a href="https://gist.github.com/receter/a72c5389595d6ce43151037b6dc03705" rel="noopener noreferrer"&gt;modalTree.ts&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Inside &lt;code&gt;ModalProvider&lt;/code&gt;, we keep a reference to an array of &lt;code&gt;ModalTreeNode&lt;/code&gt; objects (the modal tree). Based on this tree, we determine both the id of the &lt;em&gt;active&lt;/em&gt; modal and the stacking order, store them in state as &lt;code&gt;activeModalId&lt;/code&gt; and &lt;code&gt;modalOrder&lt;/code&gt;, and expose them through the context.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight diff"&gt;&lt;code&gt;// ModalProvider.tsx
&lt;span class="p"&gt;export function ModalProvider(/* … */) {
&lt;/span&gt;&lt;span class="gi"&gt;+  const modalsRef = useRef&amp;lt;ModalTreeNode[]&amp;gt;([]);
+  const [activeModalId, setActiveModalId] = useState&amp;lt;string | null&amp;gt;(null);
+  const [modalOrder, setModalOrder] = useState&amp;lt;string[]&amp;gt;([]);
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To keep the tree up to date, &lt;code&gt;Modal&lt;/code&gt; components notify &lt;code&gt;ModalProvider&lt;/code&gt; when they mount, unmount, or when their &lt;code&gt;isOpen&lt;/code&gt; state changes. This is done by calling two functions:  &lt;code&gt;registerOrUpdateModal&lt;/code&gt; or &lt;code&gt;unregisterModal&lt;/code&gt;, both of which are provided through the context.&lt;/p&gt;

&lt;p&gt;Every time the modal tree is updated, we need to re-evaluate &lt;code&gt;activeModalId&lt;/code&gt; and &lt;code&gt;modalOrder&lt;/code&gt;. To do this, we create a helper function, &lt;code&gt;update&lt;/code&gt;, which derives &lt;code&gt;activeModalId&lt;/code&gt; and &lt;code&gt;modalOrder&lt;/code&gt; from the current modal tree:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// ModalProvider.tsx&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;update&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useCallback&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;flatForest&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;flattenModalNodes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;modalsRef&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;current&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;openModals&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;flatForest&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;m&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;m&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;isOpen&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;m&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;m&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nf"&gt;setActiveModalId&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;openModals&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;openModals&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;??&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;newOrder&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;flatForest&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;m&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;m&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nf"&gt;setModalOrder&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;prevOrder&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="nx"&gt;prevOrder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;newOrder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;
      &lt;span class="nx"&gt;prevOrder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;every&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;index&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;id&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;newOrder&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;index&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="c1"&gt;// only update order if it has changed&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;prevOrder&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;newOrder&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;[]);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now we can implement &lt;code&gt;registerOrUpdateModal&lt;/code&gt; and &lt;code&gt;unregisterModal&lt;/code&gt;. By calling &lt;code&gt;update()&lt;/code&gt; in both, we ensure that &lt;code&gt;activeModalId&lt;/code&gt; and &lt;code&gt;modalOrder&lt;/code&gt; stay in sync with the internal modal tree:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// ModalProvider.tsx&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;registerOrUpdateModal&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useCallback&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;modal&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ModalInfo&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;modalsRef&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;current&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;upsertModalNode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="nx"&gt;modalsRef&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;current&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;modal&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;isOpen&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;modal&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;isOpen&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
      &lt;span class="nx"&gt;modal&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;parentId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nf"&gt;update&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;update&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;unregisterModal&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useCallback&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;modalId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;modalsRef&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;current&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;removeModalNode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;modalsRef&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;current&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;modalId&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nf"&gt;update&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;update&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;Using &lt;code&gt;useCallback&lt;/code&gt; for these functions is essential because we need stable references in order to use them safely in our &lt;code&gt;Modal&lt;/code&gt; component.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Finally, we add &lt;code&gt;activeModalId&lt;/code&gt;, &lt;code&gt;modalOrder&lt;/code&gt;, &lt;code&gt;registerOrUpdateModal&lt;/code&gt;, and &lt;code&gt;unregisterModal&lt;/code&gt; to &lt;code&gt;ModalContextType&lt;/code&gt; and and provide the relevant data via &lt;code&gt;ModalProvider&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// context.ts&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;ModalInfo&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;parentId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;isOpen&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;boolean&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;ModalContextType&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;activeModalId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;modalOrder&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;[];&lt;/span&gt;
  &lt;span class="nl"&gt;refModalContainer&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;RefObject&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;HTMLElement&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;registerOrUpdateModal&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="na"&gt;modal&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ModalInfo&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;unregisterModal&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight diff"&gt;&lt;code&gt;// ModalProvider.tsx
&lt;span class="p"&gt;const modalContextValue = {
&lt;/span&gt;&lt;span class="gi"&gt;+  activeModalId,
+  modalOrder,
&lt;/span&gt;  refModalContainer,
&lt;span class="gi"&gt;+  registerOrUpdateModal,
+  unregisterModal,
&lt;/span&gt;};
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  The modal component
&lt;/h2&gt;

&lt;p&gt;Now we can build the actual &lt;code&gt;Modal&lt;/code&gt; component!&lt;/p&gt;

&lt;p&gt;&lt;code&gt;Modal&lt;/code&gt; will have three props &lt;code&gt;isOpen&lt;/code&gt;, &lt;code&gt;onCloseRequest&lt;/code&gt;, and &lt;code&gt;children&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;isOpen&lt;/code&gt; controls whether the modal is considered &lt;em&gt;open&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;onCloseRequest(reason: string)&lt;/code&gt; is a function that can be called from anywhere withing the modal to signal that it should be closed.&lt;br&gt;
The component controlling &lt;code&gt;isOpen&lt;/code&gt; decides how to handle this request, typically by setting &lt;code&gt;isOpen&lt;/code&gt; to &lt;code&gt;false&lt;/code&gt;. The &lt;code&gt;reason&lt;/code&gt; parameter is useful for distinguishing between different close triggers and selectively ignoring them. For example, if we later add support for closing the modal when clicking outside, the &lt;code&gt;reason&lt;/code&gt; could be "click-outside", allowing a specific modal instance to ignore that event and prevent accidental closure.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;children&lt;/code&gt; represents the modal’s content and is only rendered when the modal is &lt;em&gt;open&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;For the &lt;code&gt;Modal&lt;/code&gt; component, we once again extend &lt;code&gt;ModalContext&lt;/code&gt; to provide modal-specific values that are useful deeper in the tree: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;isOpen&lt;/code&gt; and &lt;code&gt;onCloseRequest&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;isActive&lt;/code&gt;, which is &lt;code&gt;true&lt;/code&gt; when the current modal is the active one.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;level&lt;/code&gt;, which is initialized to &lt;code&gt;0&lt;/code&gt; and incremented by &lt;code&gt;1&lt;/code&gt; if a &lt;code&gt;&amp;lt;Modal&amp;gt;&lt;/code&gt; is nested inside another &lt;code&gt;&amp;lt;Modal&amp;gt;&lt;/code&gt;. For example, a &lt;code&gt;level&lt;/code&gt; of &lt;code&gt;3&lt;/code&gt; means the current modal has three ancestor modals.&lt;/li&gt;
&lt;li&gt;The unique modal ID (&lt;code&gt;modalId&lt;/code&gt;), generated using React’s &lt;a href="https://react.dev/reference/react/useId" rel="noopener noreferrer"&gt;&lt;code&gt;useId()&lt;/code&gt;&lt;/a&gt;.
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight diff"&gt;&lt;code&gt;// context.ts
&lt;span class="p"&gt;type ModalContextType = {
&lt;/span&gt;  activeModalId: string | null;
  modalOrder: string[];
  refModalContainer: RefObject&amp;lt;HTMLElement | null&amp;gt;;
  registerOrUpdateModal: (modal: ModalInfo) =&amp;gt; void;
  unregisterModal: (id: string) =&amp;gt; void;
&lt;span class="gi"&gt;+  isOpen: boolean | null;
+  onCloseRequest: ((reason: string) =&amp;gt; void) | null;
+  isActive: boolean | null;
+  level: number | null;
+  modalId: string | null;
&lt;/span&gt;} | null;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;In &lt;code&gt;ModalProvider&lt;/code&gt;, we set these fields to &lt;code&gt;null&lt;/code&gt; initially:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight diff"&gt;&lt;code&gt;// ModalProvider.tsx
&lt;span class="p"&gt;const modalContextValue = {
&lt;/span&gt;  activeModalId,
  modalOrder,
  refModalContainer,
  registerOrUpdateModal,
  unregisterModal,
&lt;span class="gi"&gt;+  // Modal-specific fields are initialized to null
+  isOpen: null,
+  onCloseRequest: null,
+  isActive: null,
+  level: null,
+  modalId: null,
&lt;/span&gt;};
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next, we create a hook that abstracts all the logic related to registering, unregistering, and updating modal-specific values in the context. The hook returns the updated context value, which we then pass to a provider in &lt;code&gt;Modal&lt;/code&gt; for consumers deeper in the tree.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// useModal.ts&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;UseModalArgs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;isOpen&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;boolean&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;onCloseRequest&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="na"&gt;reason&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;useModal&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;isOpen&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;onCloseRequest&lt;/span&gt; &lt;span class="p"&gt;}:&lt;/span&gt; &lt;span class="nx"&gt;UseModalArgs&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;modalContext&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useModalContext&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;modalId&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useId&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;isActive&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;modalContext&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;activeModalId&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;modalId&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;level&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;modalContext&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;level&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;modalContext&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;level&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;registerOrUpdateModal&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;unregisterModal&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;modalId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;parentModalId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;modalContext&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="c1"&gt;// useLayoutEffect is used here to block the browser from&lt;/span&gt;
  &lt;span class="c1"&gt;// repainting the screen before the modal is registered&lt;/span&gt;
  &lt;span class="nf"&gt;useLayoutEffect&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;registerOrUpdateModal&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;modalId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;parentId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;parentModalId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="nx"&gt;isOpen&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;registerOrUpdateModal&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;modalId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;parentModalId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;isOpen&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;

  &lt;span class="nf"&gt;useLayoutEffect&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nf"&gt;unregisterModal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;modalId&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;};&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;unregisterModal&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;modalId&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;contextValue&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;modalContext&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;isOpen&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;isActive&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;level&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;modalId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;onCloseRequest&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;contextValue&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Finally, in the &lt;code&gt;Modal&lt;/code&gt; component, we use &lt;code&gt;ModalPortal&lt;/code&gt; to render the actual HTML into the modal container. The modals children are rendered only when the modal is &lt;em&gt;open&lt;/em&gt;. For testing and demonstration purposes, we also add a simple "Close" button to close the modal. &lt;/p&gt;

&lt;p&gt;Note how &lt;code&gt;modalOrder&lt;/code&gt; is used to set a CSS custom property for the &lt;code&gt;z-index&lt;/code&gt;. While this has no effect yet, we will use it in the CSS to ensure that the visual stacking of modals stays in sync with the defined modal order. This is necessary because the rendered HTML inside the modal container does not reflect the modal order we defined.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Modal/index.tsx&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;styles&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./styles.module.css&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;ModalProps&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;isOpen&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;boolean&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;onCloseRequest&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="na"&gt;reason&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;children&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ReactNode&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;Modal&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;isOpen&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;onCloseRequest&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;children&lt;/span&gt; &lt;span class="p"&gt;}:&lt;/span&gt; &lt;span class="nx"&gt;ModalProps&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;contextValue&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useModal&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;isOpen&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;onCloseRequest&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;modalId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;modalOrder&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;contextValue&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;ModalContext&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Provider&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;contextValue&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;ModalPortal&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt;
          &lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;modalId&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
          &lt;span class="nx"&gt;style&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="p"&gt;{&lt;/span&gt;
              &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;--modal-z-index&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;modalOrder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;indexOf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;modalId&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;CSSProperties&lt;/span&gt;
          &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;isOpen&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;styles&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;modalWrapper&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
              &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;styles&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;modalWindow&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
                &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;children&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
                &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
                  &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;button&lt;/span&gt; &lt;span class="nx"&gt;onClick&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;onCloseRequest&lt;/span&gt;&lt;span class="p"&gt;?.(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;close-button&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
                    &lt;span class="nx"&gt;Close&lt;/span&gt;
                  &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/button&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;                &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;              &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;            &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;          &lt;span class="p"&gt;)}&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/ModalPortal&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/ModalContext.Provider&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Styling the modal
&lt;/h3&gt;

&lt;p&gt;Last but not least, we add some CSS to style the &lt;code&gt;Modal&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;As mentioned earlier, we use &lt;code&gt;--modal-z-index&lt;/code&gt; to control the &lt;code&gt;z-index&lt;/code&gt; of our modals. Before doing so, we need to ensure that the modals live in their own &lt;a href="https://developer.mozilla.org/en-US/docs/Web/CSS/Guides/Positioned_layout/Stacking_context" rel="noopener noreferrer"&gt;stacking context&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;To achieve this, we assign an explicit &lt;code&gt;z-index&lt;/code&gt; value to the modal container. Using a value of &lt;code&gt;0&lt;/code&gt; creates a new stacking context while preserving the normal document order.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight diff"&gt;&lt;code&gt;// App.tsx
&lt;span class="gd"&gt;-      &amp;lt;div ref={refModalContainer} /&amp;gt;
&lt;/span&gt;&lt;span class="gi"&gt;+      &amp;lt;div ref={refModalContainer} style={{ zIndex: 0, position: "relative" }} /&amp;gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Because the modal container appears &lt;em&gt;after&lt;/em&gt; the rest of the app in the DOM, a &lt;code&gt;z-index&lt;/code&gt; of &lt;code&gt;0&lt;/code&gt; still places the modals above everything else—unless another element explicitly sets a higher &lt;code&gt;z-index&lt;/code&gt; (i.e., greater than &lt;code&gt;0&lt;/code&gt;). In that case, that element would appear above the modals. For this reason, it's generally a good idea to also wrap the rest of the app in its own stacking context.&lt;/p&gt;

&lt;p&gt;All that's left now is to set &lt;code&gt;z-index&lt;/code&gt; for &lt;code&gt;.modalWrapper&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nc"&gt;.modalWrapper&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;position&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;fixed&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;z-index&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;var&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;--modal-z-index&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nl"&gt;top&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;right&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;bottom&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;left&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;overflow&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;auto&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;display&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;flex&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;align-items&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;flex-start&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;background-color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;rgba&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;0.32&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nl"&gt;padding&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0.5rem&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;.modalWrapper&lt;/code&gt; element acts as the backdrop. It uses &lt;code&gt;position: fixed&lt;/code&gt; and spans the entire viewport. We enable scrolling with &lt;code&gt;overflow: auto;&lt;/code&gt; in case the modal window exceeds the available space. Using &lt;code&gt;display: flex&lt;/code&gt; allows us to easily position the modal window within.&lt;/p&gt;

&lt;p&gt;The styles of the &lt;code&gt;.modalWindow&lt;/code&gt; are mostly a matter of taste; this is what I came up with for a simple modal window:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nc"&gt;.modalWindow&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;position&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;relative&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;box-sizing&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;border-box&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;margin&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;3rem&lt;/span&gt; &lt;span class="nb"&gt;auto&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;padding&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1rem&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;max-width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;100%&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;border-radius&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1rem&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;background&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="no"&gt;white&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;box-shadow&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt; &lt;span class="m"&gt;2px&lt;/span&gt; &lt;span class="m"&gt;4px&lt;/span&gt; &lt;span class="n"&gt;rgba&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;0.1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Alright, that's it for the first part. Now let's test the modal system.&lt;/p&gt;

&lt;h3&gt;
  
  
  Using the Modal component
&lt;/h3&gt;

&lt;p&gt;First you can remove the &lt;code&gt;ModalPortal&lt;/code&gt; from &lt;code&gt;App()&lt;/code&gt;–if you haven't already–and add a state variable to control the new &lt;code&gt;Modal&lt;/code&gt; component:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight diff"&gt;&lt;code&gt;&lt;span class="p"&gt;function App() {
&lt;/span&gt;/* … */
&lt;span class="gi"&gt;+  const [isModalOpen, setIsModalOpen] = useState(false);
&lt;/span&gt;/* … */
      &amp;lt;ModalProvider refModalContainer={refModalContainer}&amp;gt;
        {/* … */}
&lt;span class="gd"&gt;-        &amp;lt;ModalPortal /* … */ /&amp;gt;
&lt;/span&gt;&lt;span class="gi"&gt;+        &amp;lt;button onClick={() =&amp;gt; setIsModalOpen(true)}&amp;gt;Open Modal&amp;lt;/button&amp;gt;
+        &amp;lt;Modal
+          isOpen={isModalOpen}
+          onCloseRequest={() =&amp;gt; setIsModalOpen(false)}
+        &amp;gt;
+          Hello, Modal!
+        &amp;lt;/Modal&amp;gt;
&lt;/span&gt;      &amp;lt;/ModalProvider&amp;gt;
      &amp;lt;div ref={refModalContainer} /&amp;gt;
/* … */
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After clicking on "Open Modal" this is what you should see:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffri3eip9qjn89gl7vl6j.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffri3eip9qjn89gl7vl6j.png" alt="An open modal dialog with a close button" width="577" height="214"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We now have a working basic modal dialog, nice! 🥳&lt;/p&gt;

&lt;p&gt;Now let’s try a more advanced experiment to test nested modals. We’ll create a component that serves as the modal's content and includes another modal that can be opened. We then use this component recursively as the modal content. This should allow us to open an infinite chain of nested modals. If that works, we know nested modals are functioning correctly. 🙂&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;ModalContent&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;isNestedModalOpen&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setIsNestedModalOpen&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;level&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useModalContext&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;Modal&lt;/span&gt; &lt;span class="nx"&gt;level&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;level&lt;/span&gt;&lt;span class="p"&gt;}.&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/p&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;button&lt;/span&gt; &lt;span class="nx"&gt;onClick&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;setIsNestedModalOpen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="nx"&gt;Open&lt;/span&gt; &lt;span class="nx"&gt;a&lt;/span&gt; &lt;span class="nx"&gt;nested&lt;/span&gt; &lt;span class="nx"&gt;modal&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/button&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Modal&lt;/span&gt;
        &lt;span class="nx"&gt;isOpen&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;isNestedModalOpen&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="nx"&gt;onCloseRequest&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;setIsNestedModalOpen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;
      &lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;ModalContent&lt;/span&gt; &lt;span class="o"&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/Modal&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Inside &lt;code&gt;ModalContent&lt;/code&gt;, we can consume &lt;code&gt;level&lt;/code&gt; from &lt;code&gt;ModalContext&lt;/code&gt; and display it in the modal so we can see which level we’re currently on.&lt;/p&gt;

&lt;p&gt;Now, use &lt;code&gt;ModalContent&lt;/code&gt; instead of "Hello, Modal!":&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight diff"&gt;&lt;code&gt;      &amp;lt;Modal isOpen={isModalOpen} onCloseRequest={() =&amp;gt; setIsModalOpen(false)}&amp;gt;
&lt;span class="gd"&gt;-        Hello, Modal!
&lt;/span&gt;&lt;span class="gi"&gt;+        &amp;lt;ModalContent /&amp;gt;
&lt;/span&gt;      &amp;lt;/Modal&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ff56msreiitht6gdd1a5x.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ff56msreiitht6gdd1a5x.png" alt="5 nested modals on top of each other" width="641" height="292"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Yay, this works.&lt;/p&gt;

&lt;p&gt;Next up, we’ll dig into some important aspects to improve the usability and accessibility of the modals:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;How to trap focus inside a modal&lt;/li&gt;
&lt;li&gt;How to close modals via the Escape key and by clicking outside&lt;/li&gt;
&lt;li&gt;What to consider to meet modern accessibility guidelines&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Thanks for reading!
&lt;/h2&gt;

&lt;p&gt;I hope you had fun and gained some useful insights from this part of the guide on building modal dialogs in React. &lt;/p&gt;

&lt;p&gt;If you did not follow along or something wasn't that clear, you can find the full source code with working examples on my &lt;a href="https://github.com/receter" rel="noopener noreferrer"&gt;GitHub Profile&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/receter/react-modal-dialog/tree/part1" rel="noopener noreferrer"&gt;https://github.com/receter/react-modal-dialog/tree/part1&lt;/a&gt;&lt;br&gt;
(Branch: part1)&lt;/p&gt;

&lt;p&gt;I'm all ears for any thoughts you'd like to share.&lt;/p&gt;

</description>
      <category>react</category>
      <category>css</category>
      <category>a11y</category>
      <category>ux</category>
    </item>
    <item>
      <title>Why would a real pirate `npm run` when they can `npm rum` instead? 🏴‍☠️🥃</title>
      <dc:creator>Andreas Riedmüller</dc:creator>
      <pubDate>Mon, 12 Jan 2026 10:43:30 +0000</pubDate>
      <link>https://forem.com/receter/why-would-a-real-pirate-npm-run-when-they-can-npm-rum-instead-jhp</link>
      <guid>https://forem.com/receter/why-would-a-real-pirate-npm-run-when-they-can-npm-rum-instead-jhp</guid>
      <description></description>
    </item>
    <item>
      <title>Finding good things isn’t easy.</title>
      <dc:creator>Andreas Riedmüller</dc:creator>
      <pubDate>Thu, 04 Sep 2025 11:56:23 +0000</pubDate>
      <link>https://forem.com/receter/finding-good-things-isnt-easy-328c</link>
      <guid>https://forem.com/receter/finding-good-things-isnt-easy-328c</guid>
      <description>&lt;p&gt;The stuff that’s easy to find is usually monetized. And if it’s monetized, chances are it was made with money in mind. The truly good things hide behind the noise—the loud, obvious, and easy-to-digest.&lt;/p&gt;

&lt;p&gt;You have to dig. You have to put in effort to discover good software, music, art, literature, and more. There is quality in the mainstream—because there has to be. But often, even greater quality lives in the niches, where it’s free. Free from the pressure to monetize. Free from the need to meet expectations. Free from compromise.&lt;/p&gt;

&lt;p&gt;Of course, there’s also plenty of trash. But if you keep searching, if you keep digging, your taste sharpens, and with it, your world expands.&lt;/p&gt;

&lt;p&gt;Just typing “Techno” into Spotify and expecting to find greatness is naïve. The treasures lie deeper.&lt;/p&gt;

&lt;p&gt;Instead, try exploring the subgenres of techno. Ask, for example, Perplexity: “Which SoundCloud accounts have good DJ sets for this subgenre?” Suddenly your path becomes less predictable. You might stumble across a DJ with only 500 followers who happens to have uploaded an 800-play mix—his personal collection of strange and wonderful techno.&lt;/p&gt;

&lt;p&gt;The same is true for software, programming libraries, tutorials, live advice, and so on. &lt;/p&gt;

&lt;p&gt;Always remember: don’t get too comfortable. Stay a little awkward, and keep doing things in your own unique way.&lt;/p&gt;

</description>
      <category>learning</category>
      <category>coding</category>
      <category>web</category>
    </item>
    <item>
      <title>AI chats aren’t replacing thinking—they’re forcing it. Since I started using them, I capture and structure my problems more often. And wild thing: That alone is sometimes more valuable as the answer I get.</title>
      <dc:creator>Andreas Riedmüller</dc:creator>
      <pubDate>Thu, 28 Aug 2025 08:51:22 +0000</pubDate>
      <link>https://forem.com/receter/ai-chats-arent-replacing-thinking-theyre-forcing-it-since-i-started-using-them-i-capture-and-2obo</link>
      <guid>https://forem.com/receter/ai-chats-arent-replacing-thinking-theyre-forcing-it-since-i-started-using-them-i-capture-and-2obo</guid>
      <description></description>
      <category>productivity</category>
      <category>ai</category>
    </item>
    <item>
      <title>Default Component Styles</title>
      <dc:creator>Andreas Riedmüller</dc:creator>
      <pubDate>Mon, 25 Aug 2025 14:31:51 +0000</pubDate>
      <link>https://forem.com/receter/default-component-styles-72a</link>
      <guid>https://forem.com/receter/default-component-styles-72a</guid>
      <description>&lt;p&gt;I remember years ago when I first used &lt;a href="https://react-select.com/home" rel="noopener noreferrer"&gt;React Select&lt;/a&gt;, I wished it came with fewer assumptions. Instead of simply adding what I needed, I had to start by undoing what was already there.&lt;/p&gt;

&lt;p&gt;But on the flip side, having no styles at all isn’t much better. Totally unstyled components can take some time to get right, sometimes that is even more work than undoing some styles.&lt;/p&gt;

&lt;p&gt;So there’s this tension: you want to ship a sensible baseline of styles, but avoid going too far into the details.&lt;/p&gt;




&lt;p&gt;Modern component libraries often ship with both pre‑styled components and unstyled (headless) variants.&lt;/p&gt;

&lt;p&gt;Tailwind Labs for example offers &lt;a href="https://headlessui.com/" rel="noopener noreferrer"&gt;Headless UI&lt;/a&gt;—unstyled, accessible components for React and Vue—and &lt;a href="https://catalyst.tailwindui.com/docs" rel="noopener noreferrer"&gt;Catalyst&lt;/a&gt;, a React UI kit built with Tailwind (and using Headless UI) that provides opinionated, production‑ready building blocks.&lt;/p&gt;

&lt;p&gt;MUI introduced the unstyled component library &lt;a href="https://base-ui.com/react/overview/quick-start" rel="noopener noreferrer"&gt;Base UI&lt;/a&gt; fairly recently in its history.&lt;/p&gt;

&lt;p&gt;And Adobe maintains &lt;a href="https://react-spectrum.adobe.com/react-aria/index.html" rel="noopener noreferrer"&gt;React Aria&lt;/a&gt;—unstyled components and hooks focused on behavior, accessibility, and internationalization—alongside &lt;a href="https://react-spectrum.adobe.com/react-spectrum/index.html" rel="noopener noreferrer"&gt;React Spectrum&lt;/a&gt;, the fully styled React implementation of Adobe’s Spectrum design system. &lt;/p&gt;

&lt;p&gt;With System42, I want to take a similar approach: a single package, &lt;code&gt;sys42/ui&lt;/code&gt;, that provides both components with thoughtful, themeable defaults and, at the same time, hooks and clear guidance so you can easily create app‑local variants with full control over styles and markup.&lt;/p&gt;

&lt;p&gt;For every component, there are two hooks you can use to build your own component on top of the existing one: one named after the component (for example, &lt;code&gt;useButton&lt;/code&gt;), which includes styling and styling‑related props; and another prefixed with &lt;code&gt;Base&lt;/code&gt; (for example, &lt;code&gt;useBaseButton&lt;/code&gt;), which is free of styling opinions.&lt;/p&gt;

&lt;p&gt;Use the first when you just want to alter the rendering logic—for example, to create a button component that renders an &lt;code&gt;a&lt;/code&gt; instead of a &lt;code&gt;button&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;createComponent&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;../helpers&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;ButtonProps&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;useButton&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./useButton&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;ButtonA&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;createComponent&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;ButtonProps&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;a&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;a&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;hookOptions&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;elementProps&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;elementRef&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useButton&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;hookOptions&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;a&lt;/span&gt; &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;elementProps&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="na"&gt;ref&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;elementRef&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;;&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When using the base hook, you can pass a middleware‑like function as the second argument to apply style‑related props to the rendered element. Here’s an example of a &lt;code&gt;Button&lt;/code&gt; with custom styles using CSS Modules:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;BaseButtonProps&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;createComponent&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;useBaseButton&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@sys42/ui&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;cn&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@sys42/utils&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;styles&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./styles.module.css&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;Button&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;createComponent&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;BaseButtonProps&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;button&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;button&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;hookOptions&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;elementProps&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;elementRef&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useBaseButton&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;hookOptions&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;draft&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;draft&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;elementProps&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;className&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;cn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="nx"&gt;draft&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;elementProps&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nx"&gt;styles&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;button&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt; &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;elementProps&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="na"&gt;ref&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;elementRef&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;;&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;One drawback of this approach: if you name your local components identically to the library’s (for example, a local &lt;code&gt;Button&lt;/code&gt;), you must ensure your imports reference the local &lt;code&gt;Button&lt;/code&gt; rather than the library’s default &lt;code&gt;Button&lt;/code&gt; export.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1f0y7g32uc0h7l2u6mqq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1f0y7g32uc0h7l2u6mqq.png" alt="Screenshot showing the autoimport dialog of VSCode" width="538" height="102"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;One solution is to create a local alias that points to a file where you export your local components; most editors will prefer that path for auto‑imports. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgpuepwpbvzj4vdfepl1l.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgpuepwpbvzj4vdfepl1l.png" alt="Screenshot showing the autoimport dialog of VSCode" width="577" height="113"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Additionally, you could use an ESLint rule that warns when a library component is used while a local version exists.&lt;/p&gt;

&lt;p&gt;I hope you found reading this interesting. If you have any thoughts or ideas on this topic, let me know!&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>react</category>
    </item>
    <item>
      <title>System42: My Journey Building a New Design System</title>
      <dc:creator>Andreas Riedmüller</dc:creator>
      <pubDate>Wed, 20 Aug 2025 06:51:25 +0000</pubDate>
      <link>https://forem.com/receter/system42-my-journey-building-a-new-design-system-59ia</link>
      <guid>https://forem.com/receter/system42-my-journey-building-a-new-design-system-59ia</guid>
      <description>&lt;p&gt;Now, as summer comes to an end, I’m eager to continue working on System42. I’ve been working on this project for some time, with the goal of creating a design system that is well-documented, easy to use, and straightforward to extend — a set of rules and tools that help bring ideas to life quickly.&lt;/p&gt;

&lt;p&gt;While it remains experimental, it already feels much closer to what I originally envisioned than any of my earlier attempts.&lt;/p&gt;

&lt;p&gt;Two years ago, I wrote an article on &lt;a href="https://dev.to/receter/how-to-create-a-react-component-library-using-vites-library-mode-4lma"&gt;how to create a React component library using Vite’s library mode&lt;/a&gt;. It was actually a byproduct of my search for a simple—but not overly opinionated—setup for shipping a component library. I guess it must have hit a nerve, since it received way more attention than any of my other posts. And your comments helped me a lot refining the solution.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fm804twjbzsvidpudvdg4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fm804twjbzsvidpudvdg4.png" alt="A screenshot showing the stats of my top 3 posts on dev.to" width="800" height="360"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Since writing (and getting feedback) has always helped me better understand problems and find good solutions, I’ve decided to start sharing regular updates about my thoughts and progress on &lt;a href="https://github.com/receter/sys42" rel="noopener noreferrer"&gt;System42&lt;/a&gt; here.&lt;/p&gt;

&lt;p&gt;So, if you’d like to follow along with the struggles, insights, and lessons learned from someone who tries hard to build a good design system from scratch, stay tuned.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>javascript</category>
      <category>frontend</category>
      <category>design</category>
    </item>
    <item>
      <title>What helps me with end-of-day reporting</title>
      <dc:creator>Andreas Riedmüller</dc:creator>
      <pubDate>Tue, 19 Nov 2024 08:47:33 +0000</pubDate>
      <link>https://forem.com/receter/what-helps-me-with-end-of-day-reporting-155b</link>
      <guid>https://forem.com/receter/what-helps-me-with-end-of-day-reporting-155b</guid>
      <description>&lt;p&gt;&lt;strong&gt;Ever feel like your day ends and you can’t quite remember what you actually accomplished? Or do you get so absorbed in a task that you forget your original goal?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;That used to be me too. Staying focused and keeping track of my progress felt like a constant challenge.&lt;/p&gt;

&lt;p&gt;So, I built something to help: a simple web extension to keep me on track.&lt;/p&gt;

&lt;p&gt;Here’s how it works:  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;When I start working, I set my focus by writing down the task I want to accomplish.&lt;/li&gt;
&lt;li&gt;If I switch tasks, I log and update my focus.&lt;/li&gt;
&lt;li&gt;If I lose track, I glance at my focus to remind myself what’s important.
&lt;/li&gt;
&lt;li&gt;By the end of the day, I have a log of all my focused tasks and end-of-day reporting gets pretty easy.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If this sounds like something that could help you stay focused and feel more accomplished, check it out:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Google Chrome&lt;/strong&gt;&lt;br&gt;
&lt;a href="https://chromewebstore.google.com/detail/focus-log/pgoamholhbaeiokhfcchhbaicndfpcjn" rel="noopener noreferrer"&gt;https://chromewebstore.google.com/detail/focus-log/pgoamholhbaeiokhfcchhbaicndfpcjn&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Firefox&lt;/strong&gt;&lt;br&gt;
&lt;a href="https://addons.mozilla.org/de/firefox/addon/focus-log/" rel="noopener noreferrer"&gt;https://addons.mozilla.org/de/firefox/addon/focus-log/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Source (GitHub)&lt;/strong&gt;&lt;br&gt;
&lt;a href="https://github.com/receter/focus-log-extension" rel="noopener noreferrer"&gt;https://github.com/receter/focus-log-extension&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I’d love your feedback. How do you currently stay focused and keep track of what you did?&lt;/p&gt;

</description>
      <category>productivity</category>
      <category>opensource</category>
    </item>
    <item>
      <title>The Non-null Assertion Operator (!) in TypeScript</title>
      <dc:creator>Andreas Riedmüller</dc:creator>
      <pubDate>Tue, 24 Sep 2024 07:52:29 +0000</pubDate>
      <link>https://forem.com/receter/non-null-assertion-operator-in-typescript-a-handy-tool-5n0</link>
      <guid>https://forem.com/receter/non-null-assertion-operator-in-typescript-a-handy-tool-5n0</guid>
      <description>&lt;p&gt;Let’s face it—TypeScript’s type safety is amazing, but there are times when you know more about your code than TypeScript does. One situation that comes up a lot is when TypeScript insists that a value &lt;em&gt;might&lt;/em&gt; be &lt;code&gt;null&lt;/code&gt; or &lt;code&gt;undefined&lt;/code&gt;, even though you're 100% sure it's not. ﻿This is where the &lt;a href="https://www.typescriptlang.org/docs/handbook/2/everyday-types.html#non-null-assertion-operator-postfix-" rel="noopener noreferrer"&gt;Non-null Assertion Operator&lt;/a&gt; &lt;code&gt;!&lt;/code&gt; comes into play.&lt;/p&gt;

&lt;p&gt;Below is a simple code snippet demonstrating when this operator is unnecessary. TypeScript infers that video in the log statement is not null:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;video&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;video&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// TypeScript is happy.&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But if you’re working with more complex conditions, for example updating nested properties in a &lt;code&gt;produce&lt;/code&gt; call (for those who love &lt;code&gt;immer&lt;/code&gt;!), TypeScript might not infer everything perfectly. It’ll think, “What if &lt;code&gt;video&lt;/code&gt; suddenly becomes null?” To solve this, you use a type assertion:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;video&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;updatedState&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;produce&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;draftState&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;draftState&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;video&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;title&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Hello Video!&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// TypeScript complains: 'draftState.video' is possibly 'null'.ts(18047)&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;video&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;updatedState&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;produce&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;draftState&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;draftState&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;video&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;title&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Hello Video!&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// TypeScript is happy again :-)&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That &lt;code&gt;!&lt;/code&gt; is saying to TypeScript: “I know what I’m doing. Trust me, this value is not &lt;code&gt;null&lt;/code&gt; or &lt;code&gt;undefined&lt;/code&gt;.” It’s a little trick to bypass TypeScript's complaints when you know it’s safe.&lt;/p&gt;

&lt;p&gt;To be clear, I’m not saying you should sprinkle &lt;code&gt;!&lt;/code&gt; everywhere. If you use it carelessly, you might end up with bugs because you bypassed TypeScript’s safety net. But when you know your logic is solid, it’s a great tool to have.&lt;/p&gt;

&lt;p&gt;For example, when working with APIs, TypeScript might not always infer the structure exactly as you need, especially with libraries that don’t have the strongest types. Instead of wasting time creating elaborate type guards or refactoring everything, you can assert certain fields as non-null using &lt;code&gt;!&lt;/code&gt;. &lt;/p&gt;

&lt;p&gt;I use this sparingly, but if the situation requires it, &lt;code&gt;!&lt;/code&gt; saves me time and unnecessary additional checks in the code.&lt;/p&gt;

</description>
      <category>typescript</category>
    </item>
    <item>
      <title>How to Install Prettier in Your Codebase and VSCode</title>
      <dc:creator>Andreas Riedmüller</dc:creator>
      <pubDate>Wed, 14 Aug 2024 09:49:33 +0000</pubDate>
      <link>https://forem.com/receter/how-to-install-prettier-in-your-codebase-and-vscode-4c19</link>
      <guid>https://forem.com/receter/how-to-install-prettier-in-your-codebase-and-vscode-4c19</guid>
      <description>&lt;h2&gt;
  
  
  Prettier
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://prettier.io/" rel="noopener noreferrer"&gt;Prettier&lt;/a&gt; is an opinionated code formatter with support for multiple languages. &lt;/p&gt;

&lt;p&gt;Since I started using Prettier, I don't want to work code without it anymore. Despite having some concerns in the beginning (the forced line width for example), I fell in love with default settings.&lt;/p&gt;

&lt;h3&gt;
  
  
  Install and Configure Prettier
&lt;/h3&gt;

&lt;p&gt;Installing Prettier is easy, here are the steps in a nutshell. You can also follow the &lt;a href="https://prettier.io/docs/en/install.html" rel="noopener noreferrer"&gt;official installation guide&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;First you need to install the exact version of prettier locally. This ensures that everyone will use the &lt;em&gt;exact&lt;/em&gt; same version for formating code in the project.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;--save-dev&lt;/span&gt; &lt;span class="nt"&gt;--save-exact&lt;/span&gt; prettier
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next you need to create the Prettier configuration file &lt;code&gt;.prettierrc&lt;/code&gt; and &lt;code&gt;.prettierignore&lt;/code&gt; (optional) in the root of your project.&lt;/p&gt;

&lt;p&gt;You can run this command to create the default configuration file with an empty object:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;node &lt;span class="nt"&gt;--eval&lt;/span&gt; &lt;span class="s2"&gt;"fs.writeFileSync('.prettierrc','{}&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;')"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;.prettierignore&lt;/code&gt; file works in the same way as a &lt;code&gt;.gitignore&lt;/code&gt; file. In fact, Prettier already follows the rules set out in your &lt;code&gt;.gitignore&lt;/code&gt;, so you might not even need one:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;📖 By default prettier ignores files in version control systems directories (".git", ".sl", ".svn" and ".hg") and node_modules (unless the --with-node-modules CLI option is specified). Prettier will also follow rules specified in the ".gitignore" file if it exists in the same directory from which it is run.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Here is an example &lt;code&gt;.prettierignore&lt;/code&gt; to skip all HTML files:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Ignore all HTML files:&lt;/span&gt;
&lt;span class="k"&gt;**&lt;/span&gt;/&lt;span class="k"&gt;*&lt;/span&gt;.html
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Format all existing code
&lt;/h3&gt;

&lt;p&gt;Before continuing with formating the whole codebase, commit your changes. I also recommend merging all open pull requests, as a lot of files will be affected.&lt;/p&gt;

&lt;p&gt;Now run this command in the root folder of your project to format all files:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx prettier &lt;span class="nb"&gt;.&lt;/span&gt; &lt;span class="nt"&gt;--write&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;ℹ️ using &lt;code&gt;npx&lt;/code&gt; here ensures that the locally installed version of Prettier is executed. This is important if you also have prettier installed globally.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Now all your project files should be nicely formated. 🧹✨&lt;/p&gt;

&lt;h3&gt;
  
  
  Install the Prettier VSCode Extension
&lt;/h3&gt;

&lt;p&gt;Next you can setup a Prettier plugin for your IDE. I use Visual Studio Code, but there are also plugins for &lt;a href="https://prettier.io/docs/en/editors" rel="noopener noreferrer"&gt;many other editors&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;For VSCode, install this extension: &lt;a href="https://marketplace.visualstudio.com/items?itemName=esbenp.prettier-vscode" rel="noopener noreferrer"&gt;esbenp.prettier-vscode&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Having done that you can navigate to the VSCode settings and search for "formatter". Here you could set &lt;em&gt;Default Formatter&lt;/em&gt; to &lt;code&gt;esbenp.prettier-vscode&lt;/code&gt;. &lt;/p&gt;

&lt;p&gt;However, if, like me, you work on many different projects and not all of them have Prettier, you will probably leave it at the default setting (None).&lt;/p&gt;

&lt;p&gt;Instead you can set the default formatter in the local VSCode settings file (&lt;code&gt;.vscode/settings.json&lt;/code&gt;) of the projects you use prettier.&lt;/p&gt;

&lt;p&gt;To be sure any language specific global VSCode settings are overriden by the local config, you might need to specify &lt;code&gt;defaultFormatter&lt;/code&gt; for each language individually.&lt;/p&gt;

&lt;p&gt;Here is an example &lt;code&gt;.vscode/settings.json&lt;/code&gt; for reference:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"editor.defaultFormatter"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"esbenp.prettier-vscode"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"[javascript]"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"editor.defaultFormatter"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"esbenp.prettier-vscode"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"[javascriptreact]"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"editor.defaultFormatter"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"esbenp.prettier-vscode"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"[typescript]"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"editor.defaultFormatter"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"esbenp.prettier-vscode"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"[typescriptreact]"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"editor.defaultFormatter"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"esbenp.prettier-vscode"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"[css]"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"editor.defaultFormatter"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"esbenp.prettier-vscode"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"[html]"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"editor.defaultFormatter"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"esbenp.prettier-vscode"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"[jsonc]"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"editor.defaultFormatter"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"esbenp.prettier-vscode"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>javascript</category>
      <category>tutorial</category>
      <category>productivity</category>
    </item>
    <item>
      <title>The best simple JavaScript project setup to work efficiently and keep your code base clean</title>
      <dc:creator>Andreas Riedmüller</dc:creator>
      <pubDate>Tue, 30 Jul 2024 06:50:33 +0000</pubDate>
      <link>https://forem.com/receter/the-best-javascript-project-setup-to-work-efficiently-and-keep-your-code-base-clean-1mmg</link>
      <guid>https://forem.com/receter/the-best-javascript-project-setup-to-work-efficiently-and-keep-your-code-base-clean-1mmg</guid>
      <description>&lt;p&gt;To be honest, "The best…" for anything is hard to argue and in most cases not true. Nevertheless, I chose this title because I'm documenting what I currently consider to be "the best" setup for my JavaScript projects.&lt;/p&gt;

&lt;p&gt;This is not my first shot, but the result of my experiences over the last few years. I would also like to take this opportunity to thank my colleague Jay Watts for the many suggestions that have led to the current state of this setup.&lt;/p&gt;

&lt;p&gt;The setup is quite simple and most of the time default configs are used.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;🤓 Whilst there is a link to a GitHub template (React/Typescript) at the end of this article, following the steps below doesn't take long and I think it's worth doing it manually, especially the first time. If you feel like this is already to much effort, you probably don't need any of this and can just scaffold a default Vite project. You can always add these features later if you miss them.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;p&gt;Here is my take on "the best" setup in a few bullet points:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;GitHub&lt;/li&gt;
&lt;li&gt;Vite&lt;/li&gt;
&lt;li&gt;Prettier&lt;/li&gt;
&lt;li&gt;Import sorting (eslint plugin)&lt;/li&gt;
&lt;li&gt;lint-staged&lt;/li&gt;
&lt;li&gt;husky (pre-commit/pre-push hooks)&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  1. Create a new Vite project
&lt;/h2&gt;

&lt;p&gt;Vite made my life so much easier by providing a simple way to setup a new bundler project with very good default configurations. It is just so powerful that you can easily bootstrap a setup that works out of the box in seconds. For many just &lt;a href="https://vitejs.dev/guide/#scaffolding-your-first-vite-project" rel="noopener noreferrer"&gt;creating a new Vite project&lt;/a&gt; might be good enough already.&lt;/p&gt;

&lt;p&gt;To create a new Vite project all you need to do is run this command and follow the instructions:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm create vite@latest

? Project name: › my-project
? Select a framework: › React
? Select a variant: › TypeScript
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cd &lt;/span&gt;my-project
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm i
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  2. Init Git and create a &lt;code&gt;.nvmrc&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;This are the &lt;a href="https://dev.to/receter/two-things-i-do-every-time-i-set-up-a-new-node-project-1mg3"&gt;two things I do every time I setup a new node project&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Early first commit&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git init
git add &lt;span class="nt"&gt;--all&lt;/span&gt;
git commit &lt;span class="nt"&gt;-m&lt;/span&gt; &lt;span class="s2"&gt;"blank vite react/typescript project"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Create a &lt;code&gt;.nvmrc&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This file contains the version of node that is recommended for the project. If &lt;code&gt;nvm&lt;/code&gt; is installed on your system, you can run &lt;code&gt;nvm use&lt;/code&gt; in the project folder and &lt;a href="https://github.com/nvm-sh/nvm" rel="noopener noreferrer"&gt;nvm&lt;/a&gt; will automatically switch to the specified version.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;node &lt;span class="nt"&gt;--version&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; .nvmrc
git add .nvmrc
git commit &lt;span class="nt"&gt;-m&lt;/span&gt; &lt;span class="s2"&gt;"create .nvmrc file"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;💡&lt;strong&gt;Pro Tip&lt;/strong&gt; You can set up a script that will &lt;a href="https://github.com/nvm-sh/nvm#zsh" rel="noopener noreferrer"&gt;automatically call nvm use&lt;/a&gt; whenever you enter a directory that contains an &lt;code&gt;.nvmrc&lt;/code&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  3. Prettier
&lt;/h2&gt;

&lt;p&gt;Since I started using Prettier, there's no going back for me. Every time I save, my code is automatically formatted according to a uniform standard. I decided to just follow their default rules and got used to it quickly. This is a big time saver.&lt;/p&gt;

&lt;p&gt;You can read &lt;a href="https://dev.to/receter/how-to-install-prettier-in-your-codebase-and-vscode-4c19"&gt;my in depth article&lt;/a&gt; on how to install and configure Prettier (including configuring your editor) or follow the &lt;a href="https://prettier.io/docs/en/install.html" rel="noopener noreferrer"&gt;official installation guide&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;Here are the steps in a nutshell:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Install Prettier&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;--save-dev&lt;/span&gt; &lt;span class="nt"&gt;--save-exact&lt;/span&gt; prettier
node &lt;span class="nt"&gt;--eval&lt;/span&gt; &lt;span class="s2"&gt;"fs.writeFileSync('.prettierrc','{}&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;')"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git add &lt;span class="nt"&gt;--all&lt;/span&gt;
git commit &lt;span class="nt"&gt;-m&lt;/span&gt; &lt;span class="s2"&gt;"install prettier"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Format all files&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx prettier &lt;span class="nb"&gt;.&lt;/span&gt; &lt;span class="nt"&gt;--write&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git add &lt;span class="nt"&gt;--all&lt;/span&gt;
git commit &lt;span class="nt"&gt;-m&lt;/span&gt; &lt;span class="s2"&gt;"format files with prettier"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  4. Import sorting
&lt;/h2&gt;

&lt;p&gt;This is another feature I don't want to miss anymore. Especially when your editor automatically adds imports it is cumbersome to sort them manually.&lt;/p&gt;

&lt;p&gt;I have already written a separate article on this topic, which also contains my custom sorting configuration: &lt;a href="https://dev.to/receter/automatic-import-sorting-in-vscode-275m"&gt;Automatic import sorting with ESLint.&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Here are the basic steps to set up automatic import sorting for your project:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Install ESLint plugin&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;I currently use ESLint for sorting imports. My plugin of choice is &lt;code&gt;eslint-plugin-simple-import-sort&lt;/code&gt; &lt;a href="https://github.com/lydell/eslint-plugin-simple-import-sort" rel="noopener noreferrer"&gt;https://github.com/lydell/eslint-plugin-simple-import-sort&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;--save-dev&lt;/span&gt; eslint-plugin-simple-import-sort
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git add &lt;span class="nt"&gt;--all&lt;/span&gt;
git commit &lt;span class="nt"&gt;-m&lt;/span&gt; &lt;span class="s2"&gt;"install eslint-plugin-simple-import-sort"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Configuration&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Enable the plugin and rule in your eslint config:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight diff"&gt;&lt;code&gt;// .eslintrc.cjs
&lt;span class="gd"&gt;--  plugins: ["react-refresh"],
&lt;/span&gt;&lt;span class="gi"&gt;++  plugins: ["react-refresh", "eslint-plugin-simple-import-sort"],
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight diff"&gt;&lt;code&gt;// .eslintrc.cjs
  rules: {
&lt;span class="gi"&gt;++    "simple-import-sort/imports": ["error"],
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you have set up the plugin in this way, you will receive ESLint errors if the imports are not sorted according to the rules. You can now run fix for all files to automatically fix these issues and sort your imports.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx eslint &lt;span class="nt"&gt;--fix&lt;/span&gt; &lt;span class="nb"&gt;.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;I highly recommended you setup your editor to "fix" automatically every time you save a file. You can find detailed instructions to set this up for VSCode in &lt;a href="https://dev.to/receter/automatic-import-sorting-in-vscode-275m"&gt;my automatic import sorting article&lt;/a&gt;.&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git add &lt;span class="nt"&gt;--all&lt;/span&gt;
git commit &lt;span class="nt"&gt;-m&lt;/span&gt; &lt;span class="s2"&gt;"configure eslint-plugin-simple-import-sort"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  5. CSS property sorting
&lt;/h2&gt;

&lt;p&gt;I've never been a fan of sorting CSS properties alphabetically. Why should text-related styles, for example, be scattered? At the same time I do like sorting and have had my own (admittedly inconsistent) way of organizing properties.&lt;/p&gt;

&lt;p&gt;Recently I stumbled upon &lt;code&gt;prettier-plugin-css-order&lt;/code&gt; which uses &lt;a href="https://github.com/brandon-rhodes/Concentric-CSS" rel="noopener noreferrer"&gt;concentric-css&lt;/a&gt; (per default) to sort CSS properties. I just started using this, and I do have a very good feeling about it. &lt;/p&gt;

&lt;p&gt;There is also the option to sort alphabetically (🙂‍↔️) and SMACSS (another opinionated sorting approach).&lt;/p&gt;

&lt;p&gt;This is what &lt;em&gt;concentric-css&lt;/em&gt; does:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Order properties applying outside the box model, moving inward to intrinsic changes.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;ol&gt;
&lt;li&gt;Positioning&lt;/li&gt;
&lt;li&gt;Visibility&lt;/li&gt;
&lt;li&gt;Box model&lt;/li&gt;
&lt;li&gt;Dimensions&lt;/li&gt;
&lt;li&gt;Text&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Install prettier plugin&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;--save-dev&lt;/span&gt; prettier-plugin-css-order 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The docs suggest to also explicitly install &lt;code&gt;postcss&lt;/code&gt; but I think this can/should be skipped because Vite does this already.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Configuration&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;.prettierrc
{
  "plugins": ["prettier-plugin-css-order"],
  "cssDeclarationSorterKeepOverrides": false
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The config &lt;code&gt;cssDeclarationSorterKeepOverrides&lt;/code&gt; is &lt;code&gt;true&lt;/code&gt; per default, but it is recommended to turn this off if you can.&lt;/p&gt;

&lt;p&gt;Read more about what this does here: &lt;a href="https://github.com/Siilwyn/css-declaration-sorter#keepoverrides" rel="noopener noreferrer"&gt;https://github.com/Siilwyn/css-declaration-sorter#keepoverrides&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  6. Pre-Commit and Pre-Push hooks
&lt;/h2&gt;

&lt;p&gt;With &lt;a href="https://typicode.github.io/husky/" rel="noopener noreferrer"&gt;Husky&lt;/a&gt; you can run checks on the code you are about to commit/push. I use this to enforce the formatting rules for all commits and check for Typescript issues before pushing. The fact that this rules trigger from time to time is a good indicator that they are indeed very helpful for me :-)&lt;/p&gt;

&lt;p&gt;And &lt;code&gt;lint-staged&lt;/code&gt; is yet another tool that can run linters on staged files only.&lt;/p&gt;

&lt;p&gt;As per &lt;a href="https://prettier.io/docs/en/precommit" rel="noopener noreferrer"&gt;Prettier docs&lt;/a&gt; you can run this command to automatically setup &lt;a href="https://github.com/lint-staged/lint-staged" rel="noopener noreferrer"&gt;lint-staged&lt;/a&gt; and husky with a pre-commit hook. It will also add the necessary configuration to your &lt;code&gt;package.json&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx mrm@2 lint-staged
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Instead of the generated configuration I use this setup which does not allow you to commit anything with ESLint warnings and formats all files with prettier:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight diff"&gt;&lt;code&gt;// package.json
…
  "lint-staged": {
    "*.{js?(x),ts?(x)}": [
      "eslint --max-warnings 0",
      "prettier --write --ignore-unknown"
    ],
    "!*.{js?(x),ts?(x)}": "prettier --write --ignore-unknown"
  }
…
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git add &lt;span class="nt"&gt;--all&lt;/span&gt;
git commit &lt;span class="nt"&gt;-m&lt;/span&gt; &lt;span class="s2"&gt;"install/configure husky and lint-staged"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  7. TypeScript checks with pre-push hook
&lt;/h2&gt;

&lt;p&gt;Because for Typescript the context of "only staged files" is not enough, you need to run &lt;code&gt;tsc&lt;/code&gt; on the whole project instead of using lint-staged. As this takes a little longer, I do not want to run this for every commit but only before pushing code.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Add a pre-push file in the .husky directory:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;mkdir&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; .husky &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;touch&lt;/span&gt; .husky/pre-push
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Copy this script to the created file:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;#!/usr/bin/env sh&lt;/span&gt;
&lt;span class="nb"&gt;.&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;dirname&lt;/span&gt; &lt;span class="nt"&gt;--&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$0&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;/_/husky.sh"&lt;/span&gt;

&lt;span class="nb"&gt;printf&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;[PRE-PUSH HOOK] Running tsc checks. This might take a few moments.&lt;/span&gt;&lt;span class="se"&gt;\n\n&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;

npx tsc &lt;span class="nt"&gt;--noEmit&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git add &lt;span class="nt"&gt;--all&lt;/span&gt;
git commit &lt;span class="nt"&gt;-m&lt;/span&gt; &lt;span class="s2"&gt;"add pre-push TypeScript check"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  8. Claude Code
&lt;/h2&gt;

&lt;p&gt;Update 16.02.2026: Recently I work a lot with Claude Code and there are two things I have added to my template recently:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Updated &lt;code&gt;.gitingnore&lt;/code&gt; to ignore local config files
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Claude
.claude/*.local.*
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Added a hook that automatically formats and autofixes (for example for import sorting) all code in &lt;code&gt;src&lt;/code&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"hooks"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"Stop"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"hooks"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"command"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"command"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"npx prettier ./src --write &amp;amp;&amp;amp; npx eslint --fix 'src/**/*.{js,jsx,ts,tsx}'"&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Done!
&lt;/h2&gt;

&lt;p&gt;That's it, you can now start doing changes and enjoy your setup. Have fun!&lt;/p&gt;

&lt;p&gt;And please let me know if this article has helped you. I am always happy to receive feedback and hear about your experiences.&lt;/p&gt;




&lt;p&gt;GitHub Template Repository: &lt;a href="https://github.com/receter/my-vite-react-template" rel="noopener noreferrer"&gt;https://github.com/receter/my-vite-react-template&lt;/a&gt;&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>webdev</category>
      <category>tutorial</category>
      <category>productivity</category>
    </item>
    <item>
      <title>Avoiding CSS order of appearance problems with CSS Modules</title>
      <dc:creator>Andreas Riedmüller</dc:creator>
      <pubDate>Wed, 17 Apr 2024 11:42:17 +0000</pubDate>
      <link>https://forem.com/receter/avoiding-css-order-of-appearance-problems-with-css-modules-3j7p</link>
      <guid>https://forem.com/receter/avoiding-css-order-of-appearance-problems-with-css-modules-3j7p</guid>
      <description>&lt;p&gt;When I started web development, I wrote pure CSS, then I moved on to BEM (Block, Element, Modifier) methodology and LESS/SASS, and eventually adopted PostCSS and CSS Modules when I started using modern JavaScript frameworks and bundlers.&lt;/p&gt;

&lt;p&gt;For me, CSS Modules primarily solved the inconvenience of managing unwieldy long class names to avoid global namespace pollution and accidental style overrides. And despite all the new CSS libraries popping up lately, I still love the simplicity of using CSS modules.&lt;/p&gt;

&lt;p&gt;In this article I want to shed light on one challenge I've encountered when using CSS Modules:&lt;/p&gt;

&lt;h2&gt;
  
  
  Position and order of appearance
&lt;/h2&gt;

&lt;p&gt;In CSS (Cascading Style Sheets) the order in which rules appear affects the final styling of elements. Later-defined CSS rules have higher precedence and can override earlier ones. This is one of four stages in &lt;a href="https://web.dev/learn/css/the-cascade"&gt;the cascade algorithm&lt;/a&gt;, the others are specificity, origin, and importance.&lt;/p&gt;

&lt;p&gt;Sometimes, the order of CSS rules can create confusing scenarios. Imagine you have a &lt;code&gt;div&lt;/code&gt; and apply multiple classes that set &lt;code&gt;color&lt;/code&gt; like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"red blue"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Hello World&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;What color will "Hello World" have? To be able to answer this question with certainty, you need to know the order in which the classes are defined.&lt;/p&gt;

&lt;p&gt;In this case, the obvious solution is to use only one class:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"red"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Hello World&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;However, the reality looks more like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;button&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"my-fancy-button blue"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Send Hello&lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;.my-fancy-button&lt;/code&gt; is a class that defines the appearance of a fancy button, and &lt;code&gt;.blue&lt;/code&gt; is a utility class to set the color blue in this context. For this to work, you will have to to make sure that &lt;code&gt;.blue&lt;/code&gt; is defined later.&lt;/p&gt;

&lt;h2&gt;
  
  
  Bundlers
&lt;/h2&gt;

&lt;p&gt;This next example illustrates an order of appearance problem you may encounter when using CSS Modules in any bundler setup.&lt;/p&gt;

&lt;p&gt;Let's say, you create a React component and style it using a custom class. In addition the component is designed to accept a &lt;code&gt;className&lt;/code&gt; prop that can be used to pass an additional class from outside.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;button&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;styles.module.css&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;Button&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nf"&gt;concatClassNames&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;button&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;label&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Subsequently, you use this component, utilizing a helper class to override specific styles.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Button&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;components/Button&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;blue&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;../../helpers.module.css&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;BlueButton&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Button&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;blue&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="na"&gt;label&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"Click Me"&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will work like expected because bundlers typically sequence generated/imported CSS based on the first occurrence. You can think about it like a global style sheet; whenever CSS is imported, it's appended to a list of style rules.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;blue&lt;/code&gt; is imported after &lt;code&gt;Button&lt;/code&gt;, so it is added later and overwrites the color defined by the local class &lt;code&gt;button&lt;/code&gt; imported inside &lt;code&gt;Button&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;The import order is crucial here; if you would import &lt;code&gt;blue&lt;/code&gt; before &lt;code&gt;Button&lt;/code&gt;, the utility class wouldn't be able to override the color anymore:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="c1"&gt;// If the utility class is imported earlier, it doesn't &lt;/span&gt;
&lt;span class="c1"&gt;// have the ability to override styles from Button.&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;blue&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;../../helpers.module.css&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Button&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;components/Button&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Ok, so we just need to make sure to always import such utility classes last, right? &lt;/p&gt;

&lt;p&gt;In general this is true, but it might be more difficult than you expect, hang on.&lt;/p&gt;

&lt;h3&gt;
  
  
  The hidden first occurrence
&lt;/h3&gt;

&lt;p&gt;Let’s assume you import &lt;code&gt;BlueButton&lt;/code&gt; and also the same helper class &lt;code&gt;blue&lt;/code&gt; in another file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;BlueButton&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;components/BlueButton&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;MyHeading&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;components/MyHeading&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="err"&gt;…&lt;/span&gt;
&lt;span class="c1"&gt;// The utility class is imported last (in this file)&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;blue&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;../../helpers.module.css&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;MyCoolInterface&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;MyHeading&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;blue&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        Click the blue button:
      &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;MyHeading&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;BlueButton&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
      …
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Despite &lt;code&gt;blue&lt;/code&gt; being imported last &lt;em&gt;in this file&lt;/em&gt;, it's first occurrence is inside &lt;code&gt;BlueButton&lt;/code&gt;. This means that the class &lt;code&gt;blue&lt;/code&gt; will be added ahead of any CSS imported after &lt;code&gt;BlueButton&lt;/code&gt;. &lt;strong&gt;In this example the class &lt;code&gt;blue&lt;/code&gt; won't have precedence to override styles defined in &lt;code&gt;MyHeading&lt;/code&gt;.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;While in this particular case you could theoretically move the &lt;code&gt;MyHeading&lt;/code&gt; import to the top, there are situations where reordering imports merely transfers the problem to another location.&lt;/p&gt;

&lt;h3&gt;
  
  
  Avoiding hidden first occurrences
&lt;/h3&gt;

&lt;p&gt;An effective solution to avoid this problem would be a steadfast rule: &lt;strong&gt;always import CSS in an application only once, and never in multiple locations.&lt;/strong&gt; &lt;/p&gt;

&lt;p&gt;By following this rule, you ensure that each import is the first occurrence, and you can stay confident about the sequence. For each file where this rule is not followed, expect that the rules might spontaneously receive lower precedence than they currently have in your context.&lt;/p&gt;

&lt;p&gt;To use classes in multiple locations you can still import the styles once at a higher level, such as your main file or an &lt;code&gt;App&lt;/code&gt; component. Then share the classes by passing them down to children. &lt;/p&gt;

&lt;p&gt;In React, you could do this via the Context API:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;App&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./App&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;helperStyles&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;helpers.module.css&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;

&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;MyContext&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Provider&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{{&lt;/span&gt; &lt;span class="nx"&gt;helperStyles&lt;/span&gt; &lt;span class="p"&gt;}}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;App&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="err"&gt;/&lt;/span&gt;&lt;span class="na"&gt;MyContext&lt;/span&gt;&lt;span class="err"&gt;.&lt;/span&gt;&lt;span class="na"&gt;Provider&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But you could still run into order of appearance issues.&lt;/p&gt;

&lt;p&gt;Imagine you create a component &lt;code&gt;MyHeading&lt;/code&gt; that uses a class provided by &lt;code&gt;MyContext&lt;/code&gt; and in addition accepts a &lt;code&gt;className&lt;/code&gt; from outside:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;MyHeading&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="nx"&gt;children&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;helperStyles&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useContext&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;MyContext&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;h1&lt;/span&gt;
      &lt;span class="c1"&gt;// This can get you into trouble&lt;/span&gt;
      &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nf"&gt;concatClassNames&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;helperStyles&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;green&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;children&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;h1&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The file &lt;code&gt;helpers.module.css&lt;/code&gt; defines the two utility classes &lt;code&gt;blue&lt;/code&gt; and &lt;code&gt;green&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nc"&gt;.blue&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="no"&gt;blue&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nc"&gt;.green&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="no"&gt;green&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When you subsequently use &lt;code&gt;MyHeading&lt;/code&gt; and pass it the &lt;code&gt;blue&lt;/code&gt; class obtained from &lt;code&gt;MyContext&lt;/code&gt; like &lt;code&gt;&amp;lt;MyHeading className={blue} /&amp;gt;&lt;/code&gt;, the &lt;code&gt;blue&lt;/code&gt; class and the &lt;code&gt;red&lt;/code&gt; class would both be applied. And &lt;code&gt;blue&lt;/code&gt; won't have sufficient precedence to override the color because it is defined first in &lt;code&gt;helpers.module.css&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;I do like the pattern of concatenating class names across multiple levels in the component tree. But to keep this pattern intuitive you need to make sure that the precedence of rules resembles the hierarchy in your components.&lt;/p&gt;

&lt;p&gt;You can accomplish this by adhering to the aforementioned rule &lt;strong&gt;and&lt;/strong&gt; avoiding the combination of shared class names at multiple levels.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;While CSS Modules and similar tools offer elegant solutions to avoid namespace conflicts, managing the precedence of style rules is still relevant.&lt;/p&gt;

&lt;p&gt;Thank you for reading! Let me know if you found it worthwhile reading and I hope this article has piqued your curiosity. Feel free to share your thoughts and experiences on this topic in the comments below. &lt;/p&gt;

</description>
      <category>css</category>
      <category>javascript</category>
      <category>webdev</category>
      <category>architecture</category>
    </item>
  </channel>
</rss>
