<?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>DEV Community: Asmaa Almadhoun</title>
    <description>The latest articles on DEV Community by Asmaa Almadhoun (@asmaa-almadhoun).</description>
    <link>https://dev.to/asmaa-almadhoun</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%2F3772372%2Fd7abf220-7429-43b4-aa21-447f6d221cd1.jpg</url>
      <title>DEV Community: Asmaa Almadhoun</title>
      <link>https://dev.to/asmaa-almadhoun</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/asmaa-almadhoun"/>
    <language>en</language>
    <item>
      <title>AI Writes What You Ask. Architecture Survives What You Didn’t Expect</title>
      <dc:creator>Asmaa Almadhoun</dc:creator>
      <pubDate>Sat, 11 Apr 2026 08:35:33 +0000</pubDate>
      <link>https://dev.to/asmaa-almadhoun/ai-writes-what-you-ask-architecture-survives-what-you-didnt-expect-c9b</link>
      <guid>https://dev.to/asmaa-almadhoun/ai-writes-what-you-ask-architecture-survives-what-you-didnt-expect-c9b</guid>
      <description>&lt;p&gt;&lt;strong&gt;Why Human Judgment Still Matters in the Age of AI‑Assisted Development&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;AI‑assisted coding tools have transformed modern software development. They can generate boilerplate, suggest patterns, and accelerate delivery. &lt;/p&gt;

&lt;p&gt;Yet, as powerful as these tools are, they often fail in one critical dimension: design judgment. Being “smarter than AI” as a developer does not mean writing more complex code, it means designing systems that are resilient to ambiguity, change, and imperfect inputs.&lt;/p&gt;

&lt;p&gt;One of the most common and painful examples of this gap appears in how systems handle unexpected variations, such as null, undefined, empty values, or missing parameters.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The Illusion of Correctness in AI‑Generated Code&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;AI tools typically optimize for expected behavior. They assume ideal inputs, clear contracts, and happy paths. This makes their output appear correct; until reality intervenes.&lt;/p&gt;

&lt;p&gt;Consider your example:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;If I do not send exactly null, the system crashes.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;From a machine’s perspective, this may be “technically correct” code. From a human architect’s perspective, it is a design failure.&lt;/p&gt;

&lt;p&gt;A well‑designed system should not collapse because:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;null was replaced with undefined&lt;/li&gt;
&lt;li&gt;a field was omitted&lt;/li&gt;
&lt;li&gt;an empty string was passed&lt;/li&gt;
&lt;li&gt;a client behaved slightly differently than expected&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;AI‑assisted implementations often miss these nuances because they replicate patterns rather than challenge assumptions.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Clean Architecture: Designing for Reality, Not Perfection&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Robert C. Martin’s Clean Architecture: A Craftsman’s Guide to Software Structure and Design emphasizes an essential truth:&lt;/p&gt;

&lt;p&gt;Software must be designed to survive change.&lt;/p&gt;

&lt;p&gt;Clean Architecture teaches that systems should be:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Independent of frameworks&lt;/li&gt;
&lt;li&gt;Independent of UI&lt;/li&gt;
&lt;li&gt;Independent of databases&lt;/li&gt;
&lt;li&gt;Independent of external agencies&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Most importantly for your case, they should be independent of volatile input behaviour.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why This Matters for Input Validation&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;In Clean Architecture, use cases define the rules of the application. That means they are responsible for deciding what is valid, acceptable, or recoverable, not controllers, not frameworks, and certainly not AI‑generated glue code.&lt;/p&gt;

&lt;p&gt;If your system crashes because a parameter is missing or slightly different, that logic is living in the wrong place, or not living anywhere at all.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The Core Problem: Treating Inputs as Objects, Not Concepts&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;AI tends to treat input values literally:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;null ≠ undefined ≠ empty ≠ missing&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Humans, however, think conceptually:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“This value means ‘no data provided.’”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Clean Architecture encourages us to elevate that intent into the core of the system. Instead of spreading defensive checks everywhere, we define semantic boundaries:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;What does “absence” mean?&lt;/li&gt;
&lt;li&gt;Is this field required, optional, or conditional?&lt;/li&gt;
&lt;li&gt;What is the default behavior if it’s missing?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If those questions are not answered explicitly, AI has no chance of answering them correctly.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Being Smarter Than AI: Design Principles That Matter&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. Normalize at the Boundaries&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;AI often mirrors whatever structure it sees. A human architect knows better.&lt;br&gt;
At system boundaries (APIs, controllers, adapters), normalize inputs into a single internal representation. By the time data reaches your business rules, there should be one concept of “no value,” not five.&lt;/p&gt;

&lt;p&gt;This aligns directly with Clean Architecture’s rule of keeping frameworks and details at the edges.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Move Validation into Use Cases&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;AI‑generated code frequently validates inputs close to the framework layer. This is convenient and wrong.&lt;br&gt;
Clean Architecture insists that:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Business rules own validation&lt;/li&gt;
&lt;li&gt;Use cases decide what is acceptable&lt;/li&gt;
&lt;li&gt;Frameworks merely pass data along&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;When validation lives in use cases, handling null, missing, or empty values becomes a business decision, not a technical accident.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Define Explicit Contracts, Not Implicit Expectations&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;AI excels at following patterns, but struggles with unstated intent.&lt;br&gt;
Clean Architecture favors:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Explicit input models&lt;/li&gt;
&lt;li&gt;Clear invariants&lt;/li&gt;
&lt;li&gt;Defined failure modes&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If your system crashes when a value is not exactly null, it means the contract was never truly defined, only assumed.&lt;br&gt;
Humans write contracts. AI follows them.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4. Design for Change, Not Compliance&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;AI optimizes for compliance with existing code. Humans optimize for change.&lt;br&gt;
Your API may work today because clients send perfect inputs. Tomorrow:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;a mobile app changes&lt;/li&gt;
&lt;li&gt;a third‑party integration behaves differently&lt;/li&gt;
&lt;li&gt;a serialization library updates its defaults&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Clean Architecture prepares systems for that variability by isolating change and enforcing rules at the core.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Conclusion:&lt;/strong&gt; Intelligence Is in the Architecture, being smarter than AI is not about rejecting AI tools, it’s about using them responsibly.&lt;br&gt;
Let AI:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;write repetitive code&lt;/li&gt;
&lt;li&gt;scaffold structures&lt;/li&gt;
&lt;li&gt;speed up implementation&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Let humans:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;efine boundaries&lt;/li&gt;
&lt;li&gt;clarify intent&lt;/li&gt;
&lt;li&gt;design for ambiguity&lt;/li&gt;
&lt;li&gt;enforce architectural discipline&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Clean Architecture provides the mental model that AI lacks: a focus on meaning, responsibility, and change. When your system gracefully handles null, undefined, empty, and missing values, not because of defensive hacks, but because of intentional design you are operating at a level AI has not yet reached.&lt;br&gt;
And that is what real software craftsmanship looks like.&lt;/p&gt;

&lt;p&gt;Reference&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Robert C. Martin, Clean Architecture: A Craftsman’s Guide to Software Structure and Design, 2017.&lt;/p&gt;
&lt;/blockquote&gt;

</description>
      <category>ai</category>
      <category>programming</category>
      <category>architecture</category>
      <category>systemdesign</category>
    </item>
    <item>
      <title>Why fetch() Can Be Safer Than Axios After the 2026 Axios Hack</title>
      <dc:creator>Asmaa Almadhoun</dc:creator>
      <pubDate>Wed, 01 Apr 2026 09:16:10 +0000</pubDate>
      <link>https://dev.to/asmaa-almadhoun/why-fetch-can-be-safer-than-axios-after-the-2026-axios-hack-6n5</link>
      <guid>https://dev.to/asmaa-almadhoun/why-fetch-can-be-safer-than-axios-after-the-2026-axios-hack-6n5</guid>
      <description>&lt;p&gt;The question isn’t whether Axios is a “bad” library; it’s about risk surface. The Axios NPM compromise in March 2026 exposed a structural weakness in depending on third‑party libraries for something browsers already provide natively.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. Axios was compromised; fetch() cannot be published with malware&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;On March 31, 2026, attackers hijacked the npm account of Axios’s maintainer and published malicious versions (1.14.1 and 0.30.4) containing an obfuscated malware dropper. The malware executed automatically during installation.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;In contrast:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;fetch() is &lt;strong&gt;built into browsers and Node.js.&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;It &lt;strong&gt;cannot&lt;/strong&gt; be replaced or hijacked via a package manager.&lt;/li&gt;
&lt;li&gt;There is &lt;strong&gt;no installation step&lt;/strong&gt;, so no opportunity to insert post‑install malware.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Thus, fetch() has &lt;strong&gt;zero supply‑chain risk&lt;/strong&gt; compared to a package like Axios.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Axios’ supply-chain attack vector came from its dependency distribution model&lt;/strong&gt;&lt;br&gt;
The Axios compromise happened because:&lt;/p&gt;

&lt;p&gt;Attackers accessed the maintainer’s &lt;strong&gt;npm account&lt;/strong&gt;,&lt;br&gt;
Published malicious releases with a hidden dependency (plain-crypto-js),&lt;br&gt;
Inserted a &lt;strong&gt;postinstall script&lt;/strong&gt; that deployed a cross‑platform RAT.&lt;/p&gt;

&lt;p&gt;fetch() has:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;No dependencies&lt;/li&gt;
&lt;li&gt;No maintainer accounts to hijack&lt;/li&gt;
&lt;li&gt;No GitHub or npm supply chain to poison&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Therefore, using &lt;strong&gt;fetch()&lt;/strong&gt; eliminates an entire attack surface.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Axios introduced malware even though the code looked unchanged&lt;/strong&gt;&lt;br&gt;
Security investigators confirmed the attacker did not modify the Axios code directly, but only added a malicious dependency that executed during installation.&lt;/p&gt;

&lt;p&gt;This means:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Even if you audited the Axios GitHub repo, you would not see the malicious code.&lt;/li&gt;
&lt;li&gt;This type of attack is impossible with fetch() because it isn’t installed from npm.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;4. Native fetch() is now fully supported and feature‑rich, reducing the need for Axios&lt;/strong&gt;&lt;br&gt;
Historically, Axios offered conveniences like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;automatic JSON transformation&lt;/li&gt;
&lt;li&gt;request cancellation&lt;/li&gt;
&lt;li&gt;simpler syntax&lt;/li&gt;
&lt;li&gt;better error handling&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;But today:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Modern browsers and Node.js now support &lt;strong&gt;fetch()&lt;/strong&gt; with AbortController, streaming, improved error handling, and Response.json().&lt;/li&gt;
&lt;li&gt;The gap between Axios and native APIs has &lt;strong&gt;narrowed&lt;/strong&gt; significantly.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Given this parity, adding Axios creates unnecessary dependency risk.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;✔️ Summary&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Fetch is “better” than Axios from &lt;strong&gt;a security standpoint&lt;/strong&gt; because it is native, dependency‑free, cannot be hijacked through npm, and avoids the entire supply‑chain attack vector that enabled hackers to insert a remote‑access trojan into Axios’ malicious releases in March 2026&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%2F70m6mxhglrjbs6cbf7x8.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%2F70m6mxhglrjbs6cbf7x8.png" alt="Summary" width="800" height="264"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>cybersecurity</category>
      <category>javascript</category>
      <category>axios</category>
      <category>frontend</category>
    </item>
    <item>
      <title>Code Meets Creativity: Using Google Stitch as a Frontend Developer</title>
      <dc:creator>Asmaa Almadhoun</dc:creator>
      <pubDate>Tue, 24 Mar 2026 07:11:19 +0000</pubDate>
      <link>https://dev.to/asmaa-almadhoun/code-meets-creativity-using-google-stitch-as-a-frontend-developer-1997</link>
      <guid>https://dev.to/asmaa-almadhoun/code-meets-creativity-using-google-stitch-as-a-frontend-developer-1997</guid>
      <description>&lt;p&gt;As frontend developers, we’re constantly exploring tools that help us move faster, from ideation to prototypes to production‑ready UI. Google Stitch has recently had a major revamp, positioning itself as an AI‑native design assistant that promises to help us explore layouts, generate UI structures, and test ideas without jumping into code immediately.&lt;br&gt;
While Stitch isn’t a full replacement for real design tools or real designers, it can play a meaningful role in a modern frontend workflow. Here’s how you can practically use it as a developer.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Example: Creating a Landing Page With Google Stitch&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Move from idea → layout → code in minutes. Below is a simple, practical workflow showing how you can generate a landing page using Stitch, refine it, and turn it into usable frontend code.&lt;br&gt;
Each step includes a soft, rounded hybrid-style diagram to visually guide the user.&lt;/p&gt;

&lt;p&gt;1️⃣ Step 1, Open Google Stitch&lt;br&gt;
To begin, you visit Stitch and select your mode (Web or App).&lt;br&gt;
This is where you pick the model and start your design session.&lt;/p&gt;

&lt;p&gt;2️⃣ Step 2, Enter Your First Prompt&lt;br&gt;
Stitch works best with clear natural‑language instructions. You describe the structure and feel of the landing page, and Stitch generates the UI.&lt;br&gt;
Example prompt:&lt;/p&gt;

&lt;p&gt;“Create a modern landing page with a hero section, feature grid, testimonials, and a CTA. Keep it clean and easy to rebuild using React + Tailwind.”&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%2F5acut3ejy4bqqxlnxbye.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%2F5acut3ejy4bqqxlnxbye.png" alt="Stitch UI prompt" width="800" height="443"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;3️⃣ Step 3, Stitch Generates the Layout&lt;br&gt;
Stitch analyzes your prompt and files, then produces the first version of your layout.&lt;br&gt;
It typically includes full sections like the following&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%2Fejjfq1w19jm2lhtqic4u.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%2Fejjfq1w19jm2lhtqic4u.png" alt="Stitch Layout landing page main section" width="800" height="407"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;4️⃣ Step 4, Refine Using Follow‑Up Prompts&lt;br&gt;
Just like a conversation, you can refine the design by telling Stitch what to change.&lt;br&gt;
This is ideal for adjusting spacing, layout balance, color contrast, and visual hierarchy.&lt;br&gt;
Examples:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;“Increase spacing in the hero section.”&lt;/li&gt;
&lt;li&gt;“Make the color palette darker.”&lt;/li&gt;
&lt;li&gt;“Increase CTA visibility.”&lt;/li&gt;
&lt;/ul&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%2Fzcjug4pcrp3y2f2fy3qz.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%2Fzcjug4pcrp3y2f2fy3qz.png" alt="Zip file of Exporting" width="800" height="294"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;5️⃣ Step 5, Export the Code&lt;/p&gt;

&lt;p&gt;One of Stitch’s strengths is its code export ability.&lt;br&gt;
After generating your design, you can extract HTML/CSS or even React‑friendly markup to speed up your build, you will find &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Landing page (html)&lt;/li&gt;
&lt;li&gt;Design file contains rules &lt;/li&gt;
&lt;li&gt;Screen file is full Image of your landing page design&lt;/li&gt;
&lt;/ul&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%2F5y19o3akrejor7yq8vk1.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%2F5y19o3akrejor7yq8vk1.png" alt="screen shots of exporting stitch file .zip" width="684" height="219"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;6️⃣ Step 6, Paste Into Your Code Editor&lt;br&gt;
Paste the exported code into your editor (VS Code, WebStorm, etc.).&lt;br&gt;
From here, you refine the structure, add Tailwind or your design tokens, and integrate real content.&lt;/p&gt;

&lt;p&gt;🎉 Final Thoughts&lt;br&gt;
Using Google Stitch as a frontend developer dramatically accelerates:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;UI ideation&lt;/li&gt;
&lt;li&gt;Layout prototyping&lt;/li&gt;
&lt;li&gt;Early‑stage design exploration&lt;/li&gt;
&lt;li&gt;Hand‑off between design &amp;amp; code&lt;/li&gt;
&lt;li&gt;Building real landing page code faster&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Stitch doesn’t replace designers or developers, but it makes frontend workflows smoother and faster, especially when you need structure before styling.&lt;/strong&gt;&lt;/p&gt;

</description>
      <category>frontend</category>
      <category>cra</category>
      <category>ai</category>
      <category>programming</category>
    </item>
    <item>
      <title>Tailwind in Micro‑Frontends</title>
      <dc:creator>Asmaa Almadhoun</dc:creator>
      <pubDate>Fri, 13 Mar 2026 07:24:12 +0000</pubDate>
      <link>https://dev.to/asmaa-almadhoun/tailwind-in-micro-frontends-5512</link>
      <guid>https://dev.to/asmaa-almadhoun/tailwind-in-micro-frontends-5512</guid>
      <description>&lt;p&gt;From Token Drift to a Single Source of Truth&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1) Context &amp;amp; Problem&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;When you scale a Module Federation architecture (shell + multiple independently deployed micro apps), it’s tempting to let every micro app own its Tailwind config. That seems harmless until it isn’t.&lt;br&gt;
Signs you likely saw:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Token drift: primary, secondary, and other design tokens differ per micro app.&lt;/li&gt;
&lt;li&gt;Inconsistent UI: The shell and remotes looked related but not identical.&lt;/li&gt;
&lt;li&gt;Copy‑paste debt: Colors, shadows, and breakpoints duplicated across repos.&lt;/li&gt;
&lt;li&gt;Refactor pain: Changing a brand variable meant N pull requests.&lt;/li&gt;
&lt;li&gt;Conflicting semantics: primary in one app wasn’t the same hex in another.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Root causes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Each repo has its own “design system.”&lt;/li&gt;
&lt;li&gt;No enforced tokens contract shared at build time and runtime.&lt;/li&gt;
&lt;li&gt;Different teams tweaked Tailwind locally, with no common presence.&lt;/li&gt;
&lt;li&gt;Pre-flight, prefixes, and naming were sometimes inconsistent.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Result:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Slower brand rollouts, visual inconsistencies, and higher QA costs.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;2) Design Goals&lt;/strong&gt;&lt;br&gt;
To reverse the drift without killing micro‑app independence:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Single Source of Truth (SSOT) for tokens, colors, typography, spacing, shadows, breakpoints.&lt;/li&gt;
&lt;li&gt;One Tailwind prepared for every micro app import, no duplication.&lt;/li&gt;
&lt;li&gt;Runtime theming via CSS variables (dark mode, brand variants) controlled by the shell.&lt;/li&gt;
&lt;li&gt;Module Federation‑friendly: shared version of the tokens package, and predictable CSS load order.&lt;/li&gt;
&lt;li&gt;Minimal migration friction: Keep class names like text-primary, bg-colors, etc.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;3) Target Architecture (High‑Level)&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;u&gt;@org/tokens (npm package)&lt;/u&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;tokens.css → CSS variables for runtime theming.&lt;/li&gt;
&lt;li&gt;tailwind.preset.cjs → Tailwind preset mapping semantic keys (colors, shadows, screens).&lt;/li&gt;
&lt;li&gt;Optional: boxShadow, spacing, fontFamily, etc.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;u&gt;Shell (host)&lt;/u&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Loads tokens.css once and sets theme attributes (e.g., data-theme="dark").&lt;/li&gt;
&lt;li&gt;Shares @org/tokens in Module Federation to keep a single version.&lt;/li&gt;
&lt;li&gt;Enables Tailwind preflight once (recommended) and optionally a class prefix for safety.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;u&gt; Remote micro apps&lt;/u&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Import the Tailwind preset from @org/tokens.&lt;/li&gt;
&lt;li&gt;Rely on shell‑injected tokens.css (or import defensively if shell can’t).&lt;/li&gt;
&lt;li&gt;Use semantic classes (e.g., text-primary, bg-bg, shadow-card) that are all defined from tokens.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;4) The Tokens Package&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;4.1 Minimal tokens.css (runtime variables &amp;amp; themes)&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="c"&gt;/* packages/tokens/tokens.css */&lt;/span&gt;&lt;span class="nt"&gt;color-bg&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;#FFF5F0&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="err"&gt;}&lt;/span&gt;

&lt;span class="c"&gt;/* Optional dark theme (shell can toggle) */&lt;/span&gt;
&lt;span class="nd"&gt;:root&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="nt"&gt;data-theme&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;"dark"&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="py"&gt;--color-text&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;#F3F4F6&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="py"&gt;--color-bg&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;#0B1220&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="err"&gt;``&lt;/span&gt;
&lt;span class="nd"&gt;:root&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="py"&gt;--color-primary&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;#4A90E2&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="py"&gt;--color-text&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;#1F2A37&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;4.2 Minimal Tailwind preset (map variables → Tailwind theme)&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// packages/tokens/tailwind.preset.cjs&lt;/span&gt;
&lt;span class="cm"&gt;/** @type {import('tailwindcss').Config} */&lt;/span&gt;
&lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;exports&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;theme&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;extend&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;colors&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;primary&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;var(--color-primary)&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;text&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;var(--color-text)&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;bg&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;var(--color-bg)&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="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;&lt;strong&gt;5) Remote Micro App, Smallest Possible Integration&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;5.1 Federation config (Remote)&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// apps/appA/webpack.config.js&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;ModuleFederationPlugin&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;webpack&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;container&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;deps&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./package.json&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;dependencies&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;exports&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// ...&lt;/span&gt;
  &lt;span class="na"&gt;plugins&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;ModuleFederationPlugin&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;appA&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;filename&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;remoteEntry.js&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;exposes&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="s1"&gt;./Widget&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./src/Widget&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// whatever you expose&lt;/span&gt;
      &lt;span class="p"&gt;},&lt;/span&gt;
      &lt;span class="na"&gt;shared&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;react&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;singleton&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="na"&gt;requiredVersion&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;deps&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="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react-dom&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="na"&gt;singleton&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="na"&gt;requiredVersion&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;deps&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react-dom&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="c1"&gt;// 🔑 Same tokens instance/version as shell&lt;/span&gt;
        &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@org/tokens&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="na"&gt;singleton&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="na"&gt;eager&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="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;5.2 Tailwind config (Remote)&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// apps/appA/tailwind.config.cjs&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;preset&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@org/tokens&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;exports&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;presets&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;preset&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;                    &lt;span class="c1"&gt;// 🔑 central config&lt;/span&gt;
  &lt;span class="na"&gt;content&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="s1"&gt;./src/**/*.{ts,tsx,html}&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="na"&gt;prefix&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;tw-&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;                        &lt;span class="c1"&gt;// match shell if you prefix&lt;/span&gt;
  &lt;span class="na"&gt;corePlugins&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;preflight&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="c1"&gt;// let shell handle the reset&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="s2"&gt;``&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;Card&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="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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;tw-bg-bg tw-text-text tw-rounded-xl tw-p-4 tw-border tw-border-primary&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;If you’re not 100% sure the shell always loads tokens.css, you can optionally import it in the remote entry as a fallback:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@org/tokens/tokens.css&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;5.3 Stylesheet entry&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Preferred&lt;/strong&gt;: Let the shell load tokens.css globally.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Defensive&lt;/strong&gt; (if shell might not): import it here too (duplicates are harmless).
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="c"&gt;/* apps/appA/src/index.css */&lt;/span&gt;
&lt;span class="k"&gt;@import&lt;/span&gt; &lt;span class="s2"&gt;'@org/tokens/tokens.css'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;@tailwind&lt;/span&gt; &lt;span class="n"&gt;base&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;@tailwind&lt;/span&gt; &lt;span class="n"&gt;components&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;@tailwind&lt;/span&gt; &lt;span class="n"&gt;utilities&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;5.4 Component usage (Remote)&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="c1"&gt;// apps/appA/src/components/Card.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;Card&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="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="nl"&gt;title&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;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;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="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"tw-bg-cardbg tw-text-text tw-rounded-2xl tw-shadow-card tw-transition tw-border-t-4 tw-border-primary tw-p-6"&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;h3&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"tw-text-primary tw-font-bold tw-mb-2"&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;title&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;h3&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;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"tw-text-muted"&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="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="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;The classes resolve to your tokens because the preset maps Tailwind theme keys to CSS variables from tokens.css. When the shell toggles data-theme or data-brand, every remote instantly follows.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;7) Operational Tips&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Versioning &amp;amp; Changelog: Treat @org/tokens like a product.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;MAJOR for breaking renames/removals.&lt;/li&gt;
&lt;li&gt;MINOR for added tokens.&lt;/li&gt;
&lt;li&gt;PATCH for non‑breaking fixes.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Guardrails:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Lint to forbid raw hex in apps, use tokens only.&lt;/li&gt;
&lt;li&gt;Consider codemods to migrate existing classes to semantic ones.&lt;/li&gt;
&lt;li&gt;Visual regression tests in shell for critical flows (Chromatic/Playwright/etc).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Avoid CSS Leaks:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Use Tailwind prefix to reduce naming collisions.&lt;/li&gt;
&lt;li&gt;Keep preflight in shell only.&lt;/li&gt;
&lt;li&gt;If any remote uses Shadow DOM, it won’t inherit CSS variables from the document; re‑inject tokens.css inside that shadow root.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Theming Strategy:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Shell sets data-theme and data-brand at  or at each micro app’s mount container if you want per‑app themes.&lt;/li&gt;
&lt;li&gt;Tailwind utilities simply reference the semantic theme keys provided by your preset (no rebuild required at runtime).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;8) Migration Plan (Practical)&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Publish @org/tokens with tokens.css + tailwind.preset.cjs.&lt;/li&gt;
&lt;li&gt;Wire shell to load tokens.css, set theme attributes, and share the package in MF.&lt;/li&gt;
&lt;li&gt;Update each remote to use presets: [preset] and disable preflight.&lt;/li&gt;
&lt;li&gt;Replace raw hex and local color names with text-text, bg-bg, text-primary, border-accent, etc.&lt;/li&gt;
&lt;li&gt;Cut a brand update (change a token value) and watch all apps update without per‑repo edits.&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>microfrontends</category>
      <category>tailwindcss</category>
      <category>designtokens</category>
      <category>modulefederation</category>
    </item>
    <item>
      <title>From Context to Redux to Zustand: The New Era of React State Management</title>
      <dc:creator>Asmaa Almadhoun</dc:creator>
      <pubDate>Sun, 15 Feb 2026 04:27:38 +0000</pubDate>
      <link>https://dev.to/asmaa-almadhoun/from-context-to-redux-to-zustand-the-new-era-of-react-state-management-18o9</link>
      <guid>https://dev.to/asmaa-almadhoun/from-context-to-redux-to-zustand-the-new-era-of-react-state-management-18o9</guid>
      <description>&lt;p&gt;In the evolving world of React, state management has always been a central challenge. Developers first leaned on the built-in &lt;strong&gt;Context&lt;/strong&gt; API to escape prop drilling, then embraced &lt;strong&gt;Redux&lt;/strong&gt; for its strict patterns and enterprise-level predictability. &lt;/p&gt;

&lt;p&gt;But as modern apps demand speed, simplicity, and flexibility, a new contender has emerged: &lt;strong&gt;Zustand&lt;/strong&gt;. This lightweight library is reshaping how developers think about managing state, offering the efficiency of hooks, the clarity of minimal code, and the scalability needed for today’s React ecosystem.&lt;/p&gt;

&lt;h2&gt;
  
  
  🌟 Current Trend; Zustand
&lt;/h2&gt;

&lt;p&gt;Zustand is a modern state management library for React and Next.js that focuses on being small, fast, and simple. Its name means “state” in German, and its logo is a bear 🐻 symbolizing strength with minimal fuss.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why Zustand is a trend now&lt;/strong&gt;&lt;br&gt;
Zustand is gaining traction now because developers increasingly value simplicity and performance over boilerplate-heavy solutions. It’s especially popular in modern React projects, Next.js apps, and among teams that want to avoid Redux’s complexity.&lt;/p&gt;

&lt;p&gt;👉 In short: Zustand isn’t less capable, it’s just newer, less marketed, and overshadowed by Redux’s historical dominance and Context’s built-in status.&lt;/p&gt;

&lt;p&gt;🔑 Key Features&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Hooks-based API&lt;/strong&gt; → You create a store using create() and access it with custom hooks.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Minimal boilerplate&lt;/strong&gt; → No reducers, actions, or complex setup like Redux.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Performance optimized&lt;/strong&gt; → Components only re-render when the specific slice of state they use changes.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Scalable&lt;/strong&gt; → Works for both small apps and larger projects without adding complexity.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Unopinionated&lt;/strong&gt; → Lets you structure state however you want, unlike Redux’s strict patterns.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;📦 &lt;strong&gt;Installation&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;npm install zustand 
or 
yarn add zustand
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;⚡ &lt;strong&gt;Basic Example&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;import { create } from "zustand";

const useStore = create(set =&amp;gt; ({
  blogs: [],
  fetchBlogs: async () =&amp;gt; {
    const res = await fetch("/api/blogs");
    const data = await res.json();
    set({ blogs: data });
  }
}));

function BlogList() {
  const blogs = useStore(state =&amp;gt; state.blogs);
  const fetchBlogs = useStore(state =&amp;gt; state.fetchBlogs);

  React.useEffect(() =&amp;gt; {
    fetchBlogs();
  }, [fetchBlogs]);

  return (
    &amp;lt;ul&amp;gt;
      {blogs.map(blog =&amp;gt; (
        &amp;lt;li key={blog.id}&amp;gt;{blog.title}&amp;lt;/li&amp;gt;
      ))}
    &amp;lt;/ul&amp;gt;
  );
}

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

&lt;/div&gt;



&lt;h2&gt;
  
  
  🔴 Redux
&lt;/h2&gt;

&lt;p&gt;Redux has long been the “classic” solution for managing state in React. It relies on a centralized store and a strict flow of actions and reducers, which makes state predictable and easier to debug. Its ecosystem is mature, with advanced tools and middleware that support complex applications.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Advantages&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Clear and consistent state flow.&lt;/li&gt;
&lt;li&gt;Excellent debugging and developer tools.&lt;/li&gt;
&lt;li&gt;Proven reliability in large-scale projects.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Drawbacks&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Requires more setup and boilerplate code.&lt;/li&gt;
&lt;li&gt;Learning curve is steeper compared to newer libraries.&lt;/li&gt;
&lt;li&gt;Can feel heavy for smaller applications.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;📦 &lt;strong&gt;Installation&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;npm install @reduxjs/toolkit react-redux
# or
yarn add @reduxjs/toolkit react-redux
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;⚡Basic Example:&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;import { configureStore, createSlice, createAsyncThunk } from "@reduxjs/toolkit";
import { Provider, useSelector, useDispatch } from "react-redux";

// Async thunk for fetching blogs
const fetchBlogs = createAsyncThunk("blogs/fetchBlogs", async () =&amp;gt; {
  const res = await fetch("/api/blogs");
  return await res.json();
});

const blogSlice = createSlice({
  name: "blogs",
  initialState: { items: [], status: "idle" },
  reducers: {},
  extraReducers: builder =&amp;gt; {
    builder
      .addCase(fetchBlogs.pending, state =&amp;gt; {
        state.status = "loading";
      })
      .addCase(fetchBlogs.fulfilled, (state, action) =&amp;gt; {
        state.status = "succeeded";
        state.items = action.payload;
      })
      .addCase(fetchBlogs.rejected, state =&amp;gt; {
        state.status = "failed";
      });
  }
});

const store = configureStore({ reducer: { blogs: blogSlice.reducer } });

function BlogList() {
  const blogs = useSelector(state =&amp;gt; state.blogs.items);
  const status = useSelector(state =&amp;gt; state.blogs.status);
  const dispatch = useDispatch();

  React.useEffect(() =&amp;gt; {
    dispatch(fetchBlogs());
  }, [dispatch]);

  if (status === "loading") return &amp;lt;p&amp;gt;Loading...&amp;lt;/p&amp;gt;;
  if (status === "failed") return &amp;lt;p&amp;gt;Error loading blogs&amp;lt;/p&amp;gt;;

  return (
    &amp;lt;ul&amp;gt;
      {blogs.map(blog =&amp;gt; (
        &amp;lt;li key={blog.id}&amp;gt;{blog.title}&amp;lt;/li&amp;gt;
      ))}
    &amp;lt;/ul&amp;gt;
  );
}

export default function App() {
  return (
    &amp;lt;Provider store={store}&amp;gt;
      &amp;lt;BlogList /&amp;gt;
    &amp;lt;/Provider&amp;gt;
  );
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  🔵 React Context API
&lt;/h2&gt;

&lt;p&gt;The Context API is React’s built‑in mechanism for sharing data across components without passing props down manually. It’s part of React itself, so you don’t need to install anything extra. Developers often use it for global values like themes, authentication, or user preferences.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Strengths&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Comes bundled with React, no external library required.&lt;/li&gt;
&lt;li&gt;Very easy to learn and implement.&lt;/li&gt;
&lt;li&gt;Ideal for simple global state such as UI settings or logged‑in user info.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Limitations&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Can trigger unnecessary re‑renders when many components consume the same context.&lt;/li&gt;
&lt;li&gt;Doesn’t provide advanced debugging or middleware support.&lt;/li&gt;
&lt;li&gt;Not designed for complex or large‑scale state logic.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;⚡Basic Example:&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;import React, { createContext, useContext, useState, useEffect } from "react";

const BlogContext = createContext();

function BlogProvider({ children }) {
  const [blogs, setBlogs] = useState([]);

  useEffect(() =&amp;gt; {
    // Simulate fetching blogs
    fetch("/api/blogs")
      .then(res =&amp;gt; res.json())
      .then(data =&amp;gt; setBlogs(data));
  }, []);

  return (
    &amp;lt;BlogContext.Provider value={{ blogs }}&amp;gt;
      {children}
    &amp;lt;/BlogContext.Provider&amp;gt;
  );
}

function BlogList() {
  const { blogs } = useContext(BlogContext);
  return (
    &amp;lt;ul&amp;gt;
      {blogs.map(blog =&amp;gt; (
        &amp;lt;li key={blog.id}&amp;gt;{blog.title}&amp;lt;/li&amp;gt;
      ))}
    &amp;lt;/ul&amp;gt;
  );
}

export default function App() {
  return (
    &amp;lt;BlogProvider&amp;gt;
      &amp;lt;BlogList /&amp;gt;
    &amp;lt;/BlogProvider&amp;gt;
  );
}

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

&lt;/div&gt;



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

&lt;p&gt;Choosing the right state management tool in React depends on the &lt;strong&gt;scale and complexity of your project&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;For small applications or simple global values, the &lt;strong&gt;Context&lt;/strong&gt; API is more than enough. It’s built into React, easy to use, and perfect when you just need to avoid prop drilling.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;For medium‑sized projects where performance and simplicity matter, &lt;strong&gt;Zustand&lt;/strong&gt; shines. It offers a modern, lightweight approach with minimal boilerplate and efficient updates, making it a favorite among developers building fast, flexible apps.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;For large, enterprise‑level applications, &lt;strong&gt;Redux&lt;/strong&gt; remains the most reliable option. Its strict patterns, powerful devtools, and mature ecosystem make it ideal for managing complex state flows at scale.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&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%2F1ozauxhb5bgg9zsrahgh.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%2F1ozauxhb5bgg9zsrahgh.png" alt=" " width="800" height="476"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>react</category>
      <category>redux</category>
      <category>zustand</category>
      <category>management</category>
    </item>
  </channel>
</rss>
