<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[MoonUI]]></title><description><![CDATA[MoonUI]]></description><link>https://moonui.hashnode.dev</link><image><url>https://cdn.hashnode.com/uploads/logos/6ac34b0034468c95496e5d29/af9430f6-a5dc-4365-b085-d1cd6993ca20.png</url><title>MoonUI</title><link>https://moonui.hashnode.dev</link></image><generator>RSS for Node</generator><lastBuildDate>Fri, 16 Oct 2026 09:05:49 GMT</lastBuildDate><atom:link href="https://moonui.hashnode.dev/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[Why React components from npm render unstyled with Tailwind v3, and the fixes]]></title><description><![CDATA[You install a React component library, import a Button, and it renders. The text is there, the click works, and it looks like a plain browser button. No warning, no error.
I reproduced this in a clean]]></description><link>https://moonui.hashnode.dev/why-react-components-from-npm-render-unstyled-with-tailwind-v3-and-the-fixes</link><guid isPermaLink="true">https://moonui.hashnode.dev/why-react-components-from-npm-render-unstyled-with-tailwind-v3-and-the-fixes</guid><category><![CDATA[React]]></category><category><![CDATA[Tailwind CSS]]></category><dc:creator><![CDATA[MoonUI]]></dc:creator><pubDate>Tue, 06 Oct 2026 11:21:09 GMT</pubDate><content:encoded><![CDATA[<p>You install a React component library, import a <code>Button</code>, and it renders. The text is there, the click works, and it looks like a plain browser button. No warning, no error.</p>
<p>I reproduced this in a clean project with MoonUI, a React component library on Radix and Tailwind. The component was fine. Tailwind just hadn't been told enough. Here are the gaps and how to close them. Everything below uses the Tailwind v3 config format. I ran each step in a clean Vite 5 project with Tailwind 3.4 and <code>@moontra/moonui</code> 6.30.0.</p>
<h3>1. Tailwind can't see classes inside node_modules</h3>
<p>Tailwind v3 doesn't ship every utility. It scans the files listed in <code>content</code> and generates only the classes it finds. If a component library is published with Tailwind class names in its JavaScript, those names sit in <code>node_modules</code>, which your config doesn't scan by default.</p>
<p>The fix is one more glob:</p>
<pre><code class="language-js">// tailwind.config.js
module.exports = {
  content: [
    "./src/**/*.{js,ts,jsx,tsx,mdx}",
    "./node_modules/@moontra/moonui/dist/**/*.{js,mjs}",
  ],
};
</code></pre>
<p>Point it at the built output (<code>dist</code>), not the source, because that's what your bundler imports.</p>
<p>Why not put this glob inside the library's preset? We decided against it. <code>content</code> paths depend on the consumer's folder layout and package manager, and a wrong guess fails silently. It's better to ask for one explicit line.</p>
<h3>2. The class exists, the colour doesn't</h3>
<p>Libraries that support theming usually don't hardcode colours. A button uses <code>bg-primary</code>, and <code>primary</code> has to mean something in your Tailwind theme. That takes two parts:</p>
<ul>
<li>a <strong>preset</strong> that maps theme keys to CSS variables, such as <code>primary: "hsl(var(--primary) / &lt;alpha-value&gt;)"</code></li>
<li>a <strong>token stylesheet</strong> that defines <code>--primary</code> and friends for light and dark mode</li>
</ul>
<pre><code class="language-js">// tailwind.config.js
module.exports = {
  presets: [require("@moontra/moonui/tailwind-preset")],
  // ...content from step 1
  plugins: [require("tailwindcss-animate")],
};
</code></pre>
<pre><code class="language-css">/* globals.css */
@import "@moontra/moonui/tokens.css";
@tailwind base;
@tailwind components;
@tailwind utilities;
</code></pre>
<p>With the preset alone, Tailwind generates <code>bg-primary</code>, but the variable is undefined and the declaration does nothing. With the tokens alone, the variables exist but nothing uses them. You need both.</p>
<p>The animate plugin is there because Radix-based components use classes like <code>animate-in</code> and <code>fade-in-0</code> for open and close states.</p>
<h3>3. Import the tokens by their exports path</h3>
<p>The token file is published under a short <code>exports</code> subpath, so import it by that name, from CSS or from JavaScript:</p>
<pre><code class="language-css">/* from CSS */
@import "@moontra/moonui/tokens.css";
</code></pre>
<pre><code class="language-js">// or from JS, e.g. main.jsx or app/layout.tsx
import "@moontra/moonui/tokens.css";
</code></pre>
<p>Use one of the two; there is no reason to import both. In my Vite 5 run, the longer physical path (<code>@moontra/moonui/src/styles/tokens.css</code>) failed to resolve, because the package's <code>exports</code> map doesn't list it. If your setup resolves CSS imports differently, check the error message first.</p>
<h3>What each step looked like</h3>
<p>I started from an empty Vite + React project and added one step at a time. The same <code>&lt;Button&gt;Hello&lt;/Button&gt;</code> rendered like this:</p>
<ol>
<li>Package installed, nothing else: no background, no padding, a plain text button.</li>
<li>Plus the <code>content</code> glob: padding and rounded corners appear, but the background is still transparent.</li>
<li>Plus the preset and animate plugin: same result. <code>bg-primary</code> is generated, but <code>--primary</code> is undefined.</li>
<li>Plus the token import: the primary blue background and light text appear.</li>
</ol>
<h3>A quick checklist</h3>
<p>If a component from npm renders unstyled under Tailwind v3:</p>
<ol>
<li>Is the package's <code>dist</code> folder in <code>content</code>?</li>
<li>Is the library's preset (or an equivalent theme mapping) in <code>presets</code>?</li>
<li>Are the CSS variables defined, by importing the token file once?</li>
<li>Are any plugins the components need (like <code>tailwindcss-animate</code>) installed?</li>
</ol>
<p>The code is from MoonUI's free package, which is MIT: <a href="https://github.com/moonuidotdev/moonui">https://github.com/moonuidotdev/moonui</a>. If you maintain a Tailwind-based library, I'm curious how you handle this. Do you ship compiled CSS instead?</p>
<p><em>Disclosure: I wrote this with help from an AI assistant. I ran the four steps above in a clean project and checked the results myself.</em></p>
]]></content:encoded></item></channel></rss>