<?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[Modern Code]]></title><description><![CDATA[Modern Code]]></description><link>https://moderncode.hashnode.dev</link><generator>RSS for Node</generator><lastBuildDate>Wed, 04 Nov 2026 12:54:13 GMT</lastBuildDate><atom:link href="https://moderncode.hashnode.dev/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[Catch Invented React UI Imports Before They Reach Your App]]></title><description><![CDATA[Check React UI package exports with an isolated TypeScript fixture, a failing control and clear acceptance checks for coding agents.]]></description><link>https://moderncode.hashnode.dev/catch-invented-react-ui-imports-before-they-reach-your-app</link><guid isPermaLink="true">https://moderncode.hashnode.dev/catch-invented-react-ui-imports-before-they-reach-your-app</guid><category><![CDATA[TypeScript]]></category><category><![CDATA[React]]></category><dc:creator><![CDATA[cihan koc]]></dc:creator><pubDate>Fri, 30 Oct 2026 19:52:10 GMT</pubDate><enclosure url="https://cdn.hashnode.com/uploads/covers/69c6ad1eae4d2d0c2f44b3c2/79c11631-3b47-41cc-ba1d-e2eea1726950.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p><em>Cover created with AI-assisted vector code. Cover description: Trust the types. Check the imports. Button, Modal and VStack map to three different Ninna UI packages.</em></p>
<p>A small TypeScript check can catch a plausible but nonexistent component import before it becomes part of your next React feature.</p>
<p>A generated React component can look convincing while importing an API that its package does not export. The failure is easy to miss in a code review: the component name exists, the package name exists, and the combination feels reasonable. A small compiler check gives you a concrete answer before that code spreads across a feature.</p>
<p>We maintain Ninna UI. This article was drafted with AI assistance; its import examples were checked with TypeScript against installed Ninna UI 0.7.0 packages. The example is a controlled reproduction, not a claim about how often any coding agent makes this mistake.</p>
<h2>The plausible import that fails</h2>
<p>Ninna UI splits components across public packages. Button belongs to primitives, Modal belongs to overlays, and VStack belongs to layout. Here is a deliberately incorrect import:</p>
<pre><code class="language-ts">import { Modal } from "@ninna-ui/primitives";
void Modal;
</code></pre>
<p>With the installed 0.7.0 declarations, TypeScript reports TS2305: the primitives module has no exported member named Modal. The fix is to import Modal from @ninna-ui/overlays. Renaming it, installing an unrelated dependency, or adding a local declaration would conceal the underlying mismatch.</p>
<h2>Create a tiny audit file</h2>
<p>Use an existing React and TypeScript project. If these packages are missing, install only the public packages used by the example. In a new project, use the current packages; keep the lockfile so the check has a reproducible version.</p>
<pre><code class="language-bash">pnpm add @ninna-ui/core@latest @ninna-ui/primitives@latest @ninna-ui/overlays@latest @ninna-ui/layout@latest
pnpm add -D typescript @types/react @types/react-dom
</code></pre>
<p>Create ui-import-audit.ts in your project root. The file deliberately renders nothing. Referencing each import keeps the audit focused on the public values you expect the package to expose.</p>
<pre><code class="language-ts">import { Button } from "@ninna-ui/primitives";
import { Modal } from "@ninna-ui/overlays";
import { VStack } from "@ninna-ui/layout";

// This checks imports; it renders no UI.
void [Button, Modal, VStack];
</code></pre>
<h2>Give the check a clear boundary</h2>
<p>Create tsconfig.ui-audit.json beside the file. This isolated configuration checks one fixture without pulling in every application route. The bundler resolution setting is appropriate for this bundled React example; use your framework's supported configuration for the application itself.</p>
<pre><code class="language-json">{
  "compilerOptions": {
    "target": "ES2022",
    "module": "ESNext",
    "moduleResolution": "bundler",
    "lib": ["ES2022", "DOM", "DOM.Iterable"],
    "types": ["react"],
    "strict": true,
    "skipLibCheck": true,
    "noEmit": true
  },
  "include": ["ui-import-audit.ts"]
}
</code></pre>
<pre><code class="language-bash">pnpm exec tsc -p tsconfig.ui-audit.json
</code></pre>
<p>The corrected fixture should exit successfully. Then make the known wrong change: import Modal from primitives. Run the same command and confirm that it fails with TS2305. Restore the correct import and confirm success again. That negative control checks that your audit is actually compiling the file you think it is.</p>
<p>The noEmit option prevents JavaScript output. skipLibCheck skips checking declaration-file internals; it does not exempt the imports in your audit file from type checking. If the check reports a missing package instead, verify the installation and the directory from which you ran it before changing compiler settings.</p>
<h2>Give your agent an acceptance condition</h2>
<p>A package map helps an agent choose an import. An executable check helps you decide whether to accept the result. Put a short task-specific rule in the project's agent instructions, and keep the actual public API reference close to the task.</p>
<pre><code class="language-text">Before changing a React UI import:
1. Check the installed package's public export and the current docs.
2. Import Button from @ninna-ui/primitives.
3. Import Modal from @ninna-ui/overlays.
4. Import VStack from @ninna-ui/layout.
5. Run the import audit, then the application's normal typecheck and build.
Do not silence an import error with any, @ts-ignore, or a fabricated module declaration.
</code></pre>
<p>For this reproduction, TypeScript 5.9.3 and React 19.2.8 checked Ninna UI 0.7.0. The corrected three-import fixture produced no diagnostics; the deliberately incorrect Modal import produced TS2305. When you upgrade packages, rerun the check instead of assuming an old article still describes the installed release.</p>
<h2>What passing this check does not prove</h2>
<p>A correct import is only one part of a working UI. This fixture does not render a modal, open a browser, inspect CSS, or measure a bundle. It also cannot prove that published runtime code agrees perfectly with its declarations.</p>
<ul>
<li>Run the application's normal typecheck to check real props and composition.</li>
<li>Run a production build to check bundler integration and package resolution.</li>
<li>For rendered Ninna UI examples, follow the installation guide's CSS imports and root data-theme setup. An import-only fixture needs no CSS because it renders nothing.</li>
<li>Check actual interactive behavior: labels, keyboard navigation, focus movement and error states. Compiler success is not an accessibility audit.</li>
<li>Keep runtime tests for behavior you depend on. This import check complements them; it does not replace them.</li>
</ul>
<p>The useful result is modest: a plausible import becomes a checked dependency boundary. Start with the few APIs a generated feature needs, prove the check can fail, and keep the application's broader checks in the acceptance criteria.</p>
<h2>References</h2>
<p><a href="https://www.typescriptlang.org/tsconfig/moduleResolution">TypeScript: module resolution options</a></p>
<p><a href="https://www.typescriptlang.org/tsconfig/noEmit">TypeScript: noEmit</a></p>
<p><a href="https://www.typescriptlang.org/tsconfig/skipLibCheck">TypeScript: skipLibCheck</a></p>
<p><a href="https://ninna-ui.dev/getting-started/installation">Ninna UI installation and CSS setup</a></p>
<p><a href="https://ninna-ui.dev/llms.txt">Ninna UI package map and agent reference</a></p>
]]></content:encoded></item><item><title><![CDATA[Copy-Paste Components vs npm Packages: shadcn/ui vs Ninna UI in 2026
]]></title><description><![CDATA[The React component library debate used to be straightforward: pick an npm package, install it, use it. Then shadcn/ui arrived and proposed something…]]></description><link>https://moderncode.hashnode.dev/copy-paste-components-vs-npm-packages-shadcn-ui-vs-ninna-ui-in-2026</link><guid isPermaLink="true">https://moderncode.hashnode.dev/copy-paste-components-vs-npm-packages-shadcn-ui-vs-ninna-ui-in-2026</guid><dc:creator><![CDATA[cihan koc]]></dc:creator><pubDate>Wed, 01 Apr 2026 20:04:46 GMT</pubDate><enclosure url="https://cdn.hashnode.com/uploads/covers/69c6ad1eae4d2d0c2f44b3c2/ea46d275-3359-4d22-ba70-dfc87527fd80.jpg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>The React component library debate used to be straightforward: pick an npm package, install it, use it. Then shadcn/ui arrived and proposed something radical: <strong>don't install components - copy them into your codebase</strong>.</p>
<p>Two years later, both approaches have proven themselves in production. This article is an honest comparison of the copy-paste model (shadcn/ui) and the npm package model (Ninna UI) - examining the trade-offs that matter at scale.</p>
<h2>The Two Models</h2>
<h3>shadcn/ui: Copy-Paste</h3>
<p>You run a CLI command that copies React component source files directly into your project. The components use Radix UI primitives and Tailwind CSS for styling. You own every line of code.</p>
<pre><code class="language-bash">npx shadcn@latest add button dialog select
</code></pre>
<p>This creates files in your <code>components/ui/</code> directory. They're yours. Modify them freely.</p>
<h3>Ninna UI: npm Packages</h3>
<p>You install packages from npm. Components are consumed as imports. You customize via CSS custom properties, Tailwind utilities, and <code>data-slot</code> CSS selectors - without modifying source code.</p>
<pre><code class="language-bash">pnpm add @ninna-ui/primitives @ninna-ui/overlays @ninna-ui/forms
</code></pre>
<pre><code class="language-tsx">import { Button } from "@ninna-ui/primitives";
import { Modal } from "@ninna-ui/overlays";
import { Select } from "@ninna-ui/forms";
</code></pre>
<h2>The Trade-Offs</h2>
<h3>1. Updates and Maintenance</h3>
<p><strong>shadcn/ui:</strong> When a bug is fixed upstream, you have two options:</p>
<ul>
<li><p>Re-copy the component (losing your customizations)</p>
</li>
<li><p>Manually apply the patch to your local copy</p>
</li>
</ul>
<p>There's no <code>npm update</code>. No changelog. No semantic versioning. Each project has a unique fork that diverges from upstream over time.</p>
<p><strong>Ninna UI:</strong> Standard npm workflow. <code>pnpm update @ninna-ui/primitives</code> gets you bug fixes, accessibility improvements, and new features - while preserving your customizations (which live in CSS, not in component source).</p>
<pre><code class="language-bash">pnpm update @ninna-ui/primitives
# Changelog at https://ninna-ui.dev/changelog
</code></pre>
<p><strong>Verdict:</strong> npm packages win for teams that value maintenance predictability. Copy-paste wins for developers who rarely need upstream updates.</p>
<h3>2. Customization Depth</h3>
<p><strong>shadcn/ui:</strong> You own the code. You can change anything - the component structure, the HTML output, the ARIA behavior, the prop API. There's no abstraction between you and the implementation.</p>
<pre><code class="language-tsx">// You can literally rewrite the component
export function Button({ className, ...props }) {
  return (
    &lt;button
      className={cn("my-completely-custom-button-styles", className)}
      {...props}
    /&gt;
  );
}
</code></pre>
<p><strong>Ninna UI:</strong> You customize via 3 layers without touching source code:</p>
<ol>
<li><p><strong>Tailwind utilities</strong> - <code>className</code> prop on every component</p>
</li>
<li><p><strong>CSS custom properties</strong> - theme tokens (<code>--color-primary</code>, <code>--radius-lg</code>)</p>
</li>
<li><p><strong>data-slot selectors</strong> - target any internal element</p>
</li>
</ol>
<pre><code class="language-css">/* Customize any internal element via CSS */
[data-slot="trigger"] {
  border-radius: var(--radius-full);
  font-weight: 600;
}

[data-slot="content"] {
  animation: slide-down 200ms ease-out;
}
</code></pre>
<p>98 data-slot targets cover every customizable element across all 69 components - without forking a single file.</p>
<p><strong>Verdict:</strong> shadcn/ui wins for unlimited structural changes. Ninna UI wins for styling customization without the maintenance cost of owning source code.</p>
<h3>3. Cross-Project Consistency</h3>
<p><strong>shadcn/ui:</strong> Each project gets a unique copy of every component. Over time, these diverge. A <code>Button</code> in Project A is different from <code>Button</code> in Project B. Keeping them synchronized requires manual discipline or a private component library (which is... an npm package).</p>
<p><strong>Ninna UI:</strong> Every project uses the same <code>@ninna-ui/primitives</code> version. Same API, same accessibility, same behavior. Different visual styles via CSS theme presets - but the component contracts are identical.</p>
<pre><code class="language-css">/* Project A: Default theme */
@import "@ninna-ui/core/theme/presets/default.css";

/* Project B: Ocean theme */
@import "@ninna-ui/core/theme/presets/ocean.css";

/* Same components, different look */
</code></pre>
<p><strong>Verdict:</strong> npm packages win decisively for multi-project teams and agencies.</p>
<h3>4. Dependency Management</h3>
<p><strong>shadcn/ui:</strong> Each copied component may depend on specific Radix UI packages. A typical shadcn/ui project accumulates 10-15+ Radix packages:</p>
<pre><code class="language-json">{
  "@radix-ui/react-dialog": "^1.x",
  "@radix-ui/react-dropdown-menu": "^2.x",
  "@radix-ui/react-select": "^2.x",
  "@radix-ui/react-tooltip": "^1.x",
  "@radix-ui/react-popover": "^1.x",
  "@radix-ui/react-accordion": "^1.x",
  "class-variance-authority": "^0.7",
  "cmdk": "^1.x",
  "lucide-react": "^0.x"
  // ... more for each component
}
</code></pre>
<p>You manage version compatibility yourself. When Radix releases a breaking change, you update each component individually.</p>
<p><strong>Ninna UI:</strong> Radix is an internal implementation detail. You never import it. You never manage its versions. Ninna UI wraps 11 Radix primitives behind clean interfaces:</p>
<pre><code class="language-json">{
  "@ninna-ui/primitives": "^0.4.1",
  "@ninna-ui/overlays": "^0.4.1",
  "@ninna-ui/forms": "^0.4.1"
}
</code></pre>
<p>Three dependencies instead of fifteen. Radix version management is Ninna UI's responsibility, not yours.</p>
<p><strong>Verdict:</strong> npm packages win for dependency hygiene. Copy-paste forces you to be a Radix version manager.</p>
<h3>5. Bundle Size</h3>
<p><strong>shadcn/ui:</strong> You only include the components you use, and since they're local files, tree-shaking is perfect. No unused code reaches the bundle.</p>
<p>However, each component pulls its own Radix dependency, and multiple components may include overlapping utility code (cn(), cva(), etc.).</p>
<p><strong>Ninna UI:</strong> 12 tree-shakeable ESM packages with <code>sideEffects: false</code>. Import only what you use - unused components are eliminated by your bundler.</p>
<p>The theming layer is pure CSS (zero JavaScript), which means your theming overhead is literally 0 KB of JavaScript. shadcn/ui's theming is also CSS-based, so this is roughly equivalent.</p>
<p><strong>Verdict:</strong> Roughly equal. Both approaches tree-shake well. Ninna UI has a slight edge because Radix dependencies are deduplicated internally.</p>
<h3>6. TypeScript Experience</h3>
<p><strong>shadcn/ui:</strong> Types depend on how well you maintain the copied code. Out of the box, components use <code>cva</code> for variant typing, which provides basic prop safety. But types can degrade as you modify components.</p>
<p><strong>Ninna UI:</strong> Full TypeScript generics on every component, maintained by the library team. Generic <code>Select&lt;T&gt;</code>, discriminated union props, strict event handlers:</p>
<pre><code class="language-tsx">type Role = "admin" | "editor" | "viewer";

&lt;Select&lt;Role&gt;
  options={[
    { value: "admin", label: "Admin" },
    { value: "editor", label: "Editor" },
  ]}
  onChange={(role) =&gt; {
    // role is typed as Role, not string
  }}
/&gt;
</code></pre>
<p><strong>Verdict:</strong> Ninna UI wins for type depth and consistency. shadcn/ui types are "good enough" but degrade with customization.</p>
<h3>7. Accessibility</h3>
<p>Both use Radix UI primitives, so the accessibility foundation is identical. The difference is maintenance:</p>
<p><strong>shadcn/ui:</strong> When Radix improves accessibility (new ARIA patterns, better screen reader support), you must manually update your copied components to benefit.</p>
<p><strong>Ninna UI:</strong> Accessibility improvements ship via <code>npm update</code>. You get them automatically.</p>
<p><strong>Verdict:</strong> Equivalent at install time. Ninna UI wins over time because updates are automatic.</p>
<h2>Decision Framework</h2>
<p>Choose <strong>shadcn/ui</strong> if:</p>
<ul>
<li><p>You're a solo developer or small team</p>
</li>
<li><p>You want unlimited structural control over components</p>
</li>
<li><p>You rarely need upstream updates</p>
</li>
<li><p>You're comfortable managing Radix dependencies</p>
</li>
<li><p>You enjoy customizing component internals</p>
</li>
</ul>
<p>Choose <strong>Ninna UI</strong> if:</p>
<ul>
<li><p>You work across multiple projects</p>
</li>
<li><p>You want standard npm maintenance (<code>update</code>, <code>audit</code>, semver)</p>
</li>
<li><p>You prefer CSS customization over source code modification</p>
</li>
<li><p>You want Radix accessibility without managing Radix directly</p>
</li>
<li><p>You need consistent component behavior across your organization</p>
</li>
</ul>
<p>Choose <strong>both</strong> if:</p>
<ul>
<li><p>You want the npm package model for most components</p>
</li>
<li><p>But need to fork specific components for edge cases</p>
</li>
</ul>
<p>Ninna UI's <code>data-slot</code> CSS API means you'll rarely need to fork. But when you do, nothing stops you from copying one component's source and customizing it.</p>
<h2>The Bigger Picture</h2>
<p>The copy-paste vs npm debate isn't really about shadcn/ui vs Ninna UI. It's about two different philosophies:</p>
<p><strong>Copy-paste says:</strong> "Libraries are constraints. Own your code."</p>
<p><strong>npm packages say:</strong> "Libraries are leverage. Own your product."</p>
<p>Both are valid. But the npm model has 20 years of proven infrastructure - semantic versioning, changelogs, automated updates, dependency auditing, security patches - that the copy-paste model intentionally abandons.</p>
<p>In 2026, with React Server Components, Tailwind CSS v4, and the increasing complexity of web accessibility requirements, the case for professional-grade npm packages has never been stronger.</p>
<h2>Try Ninna UI</h2>
<pre><code class="language-bash">npx @ninna-ui/cli init my-app
</code></pre>
<p>→ <a href="https://ninna-ui.dev/getting-started/installation">Documentation</a> → <a href="https://ninna-ui.dev/compare/shadcn-vs-ninna-ui">shadcn/ui vs Ninna UI comparison</a> → <a href="https://ninna-ui.dev/compare">All library comparisons</a></p>
<hr />
]]></content:encoded></item><item><title><![CDATA[Top 5 Free Tailwind Component Libraries in 2026]]></title><description><![CDATA[The best free, open-source Tailwind CSS component libraries for React developers in 2026. Comparing DaisyUI, shadcn/ui, Ninna UI, Flowbite, and Prelin]]></description><link>https://moderncode.hashnode.dev/top-5-free-tailwind-component-libraries-in-2026</link><guid isPermaLink="true">https://moderncode.hashnode.dev/top-5-free-tailwind-component-libraries-in-2026</guid><category><![CDATA[Tailwind CSS]]></category><category><![CDATA[React]]></category><category><![CDATA[Web Development]]></category><category><![CDATA[webdev]]></category><category><![CDATA[Frontend Development]]></category><category><![CDATA[frontend]]></category><dc:creator><![CDATA[cihan koc]]></dc:creator><pubDate>Fri, 27 Mar 2026 16:35:38 GMT</pubDate><content:encoded><![CDATA[<p>Building a production app shouldn't require a four-figure UI kit license. The Tailwind CSS ecosystem in 2026 has matured to the point where free, open-source component libraries rival-and in many cases surpass-their commercial counterparts.</p>
<p>Here are the 5 best free Tailwind CSS component libraries you can use today, ranked by how well they solve the real problems developers face: <strong>accessibility</strong>, <strong>theming</strong>, <strong>type safety</strong>, and <strong>Tailwind v4 compatibility</strong>.</p>
<h2>1. Ninna UI - Zero-Runtime React Components</h2>
<p><strong>GitHub:</strong> <a href="https://github.com/ninna-ui/ninna-ui">github.com/ninna-ui/ninna-ui</a> · <strong>License:</strong> MIT · <strong>Stars:</strong> Growing fast</p>
<p>Ninna UI is a full React component library purpose-built for Tailwind CSS v4 and React 19. Unlike CSS-only libraries, every component is a real React element with <code>forwardRef</code>, <code>displayName</code>, TypeScript generics, and Radix-powered accessibility.</p>
<h3>Why it stands out</h3>
<p>The killer feature is <strong>zero-runtime theming</strong>. Most React UI libraries require a <code>ThemeProvider</code> wrapper that adds JavaScript overhead and hydration cost. Ninna UI eliminates this entirely - your design system is a single CSS import:</p>
<pre><code class="language-css">@import "tailwindcss";
@import "@ninna-ui/core/theme/presets/default.css";
</code></pre>
<p>That's the complete setup. No <code>tailwind.config.ts</code>. No <code>ChakraProvider</code>. No <code>createTheme()</code>. Just CSS.</p>
<h3>What you get (for free)</h3>
<ul>
<li><p><strong>69 components</strong> across 12 tree-shakeable packages</p>
</li>
<li><p><strong>5 theme presets</strong> (Default, Ocean, Sunset, Forest, Minimal) - all oklch-based</p>
</li>
<li><p><strong>WCAG 2.1 AA</strong> accessibility on every component</p>
</li>
<li><p><strong>98 data-slot CSS targets</strong> for customizing any internal element</p>
</li>
<li><p><strong>700+ tests</strong> covering every component</p>
</li>
<li><p><strong>CLI scaffolding</strong> - <code>npx @ninna-ui/cli init my-app</code></p>
</li>
</ul>
<pre><code class="language-tsx">import { Button, Badge } from "@ninna-ui/primitives";
import { Modal } from "@ninna-ui/overlays";
import { DataTable } from "@ninna-ui/data-display";
</code></pre>
<h3>Best for</h3>
<p>React teams who want npm-installable, accessible components with native Tailwind CSS v4 theming and zero configuration overhead.</p>
<p>→ <a href="https://ninna-ui.dev/getting-started/installation">Get started</a> · <a href="https://ninna-ui.dev/examples">Live examples</a></p>
<hr />
<h2>2. DaisyUI - The Beloved CSS Plugin</h2>
<p><strong>GitHub:</strong> <a href="https://github.com/saadeghi/daisyui">github.com/saadeghi/daisyui</a> · <strong>License:</strong> MIT · <strong>Stars:</strong> 35k+</p>
<p>DaisyUI v5 is the most popular Tailwind CSS component plugin. It adds semantic class names to Tailwind - <code>btn</code>, <code>card</code>, <code>modal</code>, <code>badge</code> - so you write less utility markup.</p>
<h3>Why it stands out</h3>
<p>DaisyUI's approach is beautifully simple: it's a Tailwind plugin that adds component classes. Zero JavaScript. Framework-agnostic. Works with any HTML. The 35 built-in themes (now with oklch colors in v5) let you switch design flavors instantly.</p>
<h3>Limitations to consider</h3>
<ul>
<li><p><strong>No accessibility</strong> - CSS classes can't add ARIA attributes, manage focus, or handle keyboard navigation</p>
</li>
<li><p><strong>No TypeScript safety</strong> - component "APIs" are class name strings</p>
</li>
<li><p><strong>Interactive components require manual JS</strong> - dropdowns, modals, selects need your own implementation</p>
</li>
<li><p><strong>Not React-native</strong> - you're working with class names, not component props</p>
</li>
</ul>
<h3>Best for</h3>
<p>Rapid prototyping, static sites, and projects where you handle interactivity and accessibility yourself.</p>
<hr />
<h2>3. shadcn/ui - Copy-Paste Components</h2>
<p><strong>GitHub:</strong> <a href="https://github.com/shadcn-ui/ui">github.com/shadcn-ui/ui</a> · <strong>License:</strong> MIT · <strong>Stars:</strong> 80k+</p>
<p>shadcn/ui popularized a radical idea: instead of installing components from npm, you copy their source code directly into your project. A CLI handles the copying, and you get full ownership of every line.</p>
<h3>Why it stands out</h3>
<p>The code-ownership model means you can customize anything without fighting library abstractions. Components are built on Radix UI primitives with Tailwind CSS styling, giving you solid accessibility foundations.</p>
<h3>Limitations to consider</h3>
<ul>
<li><p><strong>Manual updates</strong> - no <code>npm update</code>. When bugs are fixed upstream, you re-copy or manually patch</p>
</li>
<li><p><strong>Dependency sprawl</strong> - each component may pull in specific Radix packages as peer deps</p>
</li>
<li><p><strong>No versioning</strong> - no changelogs, no semantic versioning, no migration guides</p>
</li>
<li><p><strong>Per-project forks</strong> - every project gets a unique copy, making consistency across projects challenging</p>
</li>
</ul>
<h3>Best for</h3>
<p>Solo developers or small teams who want complete control and are comfortable maintaining their own component code.</p>
<hr />
<h2>4. Flowbite - Cross-Framework UI Kit</h2>
<p><strong>GitHub:</strong> <a href="https://github.com/themesberg/flowbite">github.com/themesberg/flowbite</a> · <strong>License:</strong> MIT (core) · <strong>Stars:</strong> 8k+</p>
<p>Flowbite provides Tailwind CSS components in vanilla HTML/JS with official React, Vue, and Svelte wrappers. The free tier is generous, though some advanced components and templates are behind a paid plan.</p>
<h3>Why it stands out</h3>
<p>If you work across frameworks - React for the app, Astro for the marketing site, Svelte for the dashboard - Flowbite gives you a consistent visual language everywhere. The vanilla core means components work with anything.</p>
<h3>Limitations to consider</h3>
<ul>
<li><p><strong>React wrappers are less polished</strong> than the vanilla HTML versions</p>
</li>
<li><p><strong>Accessibility coverage varies</strong> by component</p>
</li>
<li><p><strong>Some pro components are paywalled</strong></p>
</li>
<li><p><strong>Tailwind v4 support is still maturing</strong></p>
</li>
</ul>
<h3>Best for</h3>
<p>Multi-framework teams and projects that need consistent Tailwind components across React, Vue, and Svelte.</p>
<hr />
<h2>5. Preline UI - Large Component Library</h2>
<p><strong>GitHub:</strong> <a href="https://github.com/htmlstreamofficial/preline">github.com/htmlstreamofficial/preline</a> · <strong>License:</strong> MIT · <strong>Stars:</strong> 5k+</p>
<p>Preline offers 70+ Tailwind CSS components with a vanilla JS plugin approach. It includes a large collection of marketing blocks, application UI, and landing page components.</p>
<h3>Why it stands out</h3>
<p>Preline has one of the largest free component collections in the Tailwind ecosystem. The marketing-focused blocks (hero sections, pricing tables, feature grids, testimonials) are particularly useful for landing pages.</p>
<h3>Limitations to consider</h3>
<ul>
<li><p><strong>Vanilla JS plugin</strong> - not React-native, requires manual integration</p>
</li>
<li><p><strong>Accessibility is partial</strong> - not all interactive components have proper ARIA</p>
</li>
<li><p><strong>TypeScript integration limited</strong></p>
</li>
<li><p><strong>Less active maintenance</strong> compared to top-tier libraries</p>
</li>
</ul>
<h3>Best for</h3>
<p>Landing pages, marketing sites, and projects that need a large variety of pre-built sections.</p>
<hr />
<h2>Quick Comparison</h2>
<table>
<thead>
<tr>
<th></th>
<th>Ninna UI</th>
<th>DaisyUI</th>
<th>shadcn/ui</th>
<th>Flowbite</th>
<th>Preline</th>
</tr>
</thead>
<tbody><tr>
<td><strong>Price</strong></td>
<td>Free (MIT)</td>
<td>Free (MIT)</td>
<td>Free (MIT)</td>
<td>Free core</td>
<td>Free (MIT)</td>
</tr>
<tr>
<td><strong>Components</strong></td>
<td>69</td>
<td>65+</td>
<td>40+</td>
<td>44+</td>
<td>70+</td>
</tr>
<tr>
<td><strong>React-native</strong></td>
<td>✅</td>
<td>❌</td>
<td>✅</td>
<td>Wrapper</td>
<td>❌</td>
</tr>
<tr>
<td><strong>Accessibility</strong></td>
<td>WCAG AA</td>
<td>None</td>
<td>Radix-based</td>
<td>Partial</td>
<td>Partial</td>
</tr>
<tr>
<td><strong>Tailwind v4</strong></td>
<td>Native</td>
<td>v5 plugin</td>
<td>v3 + v4</td>
<td>Early</td>
<td>v3 + v4</td>
</tr>
<tr>
<td><strong>TypeScript</strong></td>
<td>Full</td>
<td>N/A</td>
<td>Good</td>
<td>Partial</td>
<td>Limited</td>
</tr>
<tr>
<td><strong>Theming</strong></td>
<td>5 CSS presets</td>
<td>35 themes</td>
<td>CSS vars</td>
<td>CSS vars</td>
<td>CSS vars</td>
</tr>
<tr>
<td><strong>Runtime cost</strong></td>
<td>Zero</td>
<td>Zero</td>
<td>Radix runtime</td>
<td>Small JS</td>
<td>Small JS</td>
</tr>
<tr>
<td><strong>Updates</strong></td>
<td><code>npm update</code></td>
<td><code>npm update</code></td>
<td>Manual copy</td>
<td><code>npm update</code></td>
<td><code>npm update</code></td>
</tr>
</tbody></table>
<h2>The Bottom Line</h2>
<p>Every library on this list is free and MIT-licensed. The choice comes down to your stack and priorities:</p>
<ul>
<li><p><strong>React + best DX + accessibility</strong> → Ninna UI</p>
</li>
<li><p><strong>Any framework + CSS-only simplicity</strong> → DaisyUI</p>
</li>
<li><p><strong>Full code ownership</strong> → shadcn/ui</p>
</li>
<li><p><strong>Multi-framework consistency</strong> → Flowbite</p>
</li>
<li><p><strong>Maximum component variety</strong> → Preline</p>
</li>
</ul>
<p>The trend in 2026 is unmistakable: CSS-first theming is winning over JavaScript runtime approaches. Libraries that embrace Tailwind CSS v4's native capabilities - <code>@import</code> configuration, oklch colors, CSS-only dark mode - deliver better performance and simpler developer experience.</p>
]]></content:encoded></item><item><title><![CDATA[TailwindCSS Libraries You Should Know and Use in 2026]]></title><description><![CDATA[Tailwind CSS v4 didn't just improve the framework - it reshaped the entire ecosystem around it. The move to CSS-first configuration, the Lightning CSS…]]></description><link>https://moderncode.hashnode.dev/tailwindcss-libraries-you-should-know-and-use-in-2026</link><guid isPermaLink="true">https://moderncode.hashnode.dev/tailwindcss-libraries-you-should-know-and-use-in-2026</guid><category><![CDATA[Tailwind CSS]]></category><category><![CDATA[React]]></category><category><![CDATA[Web Development]]></category><category><![CDATA[webdev]]></category><category><![CDATA[Frontend Development]]></category><category><![CDATA[frontend]]></category><category><![CDATA[JavaScript]]></category><category><![CDATA[Next.js]]></category><dc:creator><![CDATA[cihan koc]]></dc:creator><pubDate>Fri, 27 Mar 2026 16:31:58 GMT</pubDate><content:encoded><![CDATA[<p>Tailwind CSS v4 didn't just improve the framework - it reshaped the entire ecosystem around it. The move to CSS-first configuration, the Lightning CSS engine, and native oklch color support have made some libraries more relevant and others obsolete.</p>
<p>This isn't another "top 10 UI kits" list. This is a curated guide to the <strong>libraries, plugins, and tools</strong> that make Tailwind CSS v4 development genuinely faster and better in 2026.</p>
<h2>Component Libraries</h2>
<h3>Ninna UI - The CSS-First React Library</h3>
<p>If you're building with React 19 and Tailwind CSS v4, Ninna UI is the library that was built for this exact stack. 69 accessible components, zero-runtime theming, oklch colors, and a setup that takes literally two lines of CSS.</p>
<pre><code class="language-css">@import "tailwindcss";
@import "@ninna-ui/core/theme/presets/default.css";
</code></pre>
<p>What makes it different from every other React component library: <strong>no ThemeProvider</strong>. Your design system is a CSS file, not a JavaScript object. That means zero hydration cost, instant theme switching, and compatibility with any SSR framework.</p>
<ul>
<li><p>12 tree-shakeable packages - install only what you use</p>
</li>
<li><p>Radix UI accessibility internals (zero API leakage)</p>
</li>
<li><p>5 theme presets with oklch perceptual colors</p>
</li>
<li><p>98 <code>data-slot</code> CSS targets for granular customization</p>
</li>
<li><p>Full TypeScript generics on every component</p>
</li>
</ul>
<p>-&gt;<a href="https://ninna-ui.dev">ninna-ui.dev</a></p>
<h3>DaisyUI v5 - Semantic CSS Classes</h3>
<p>DaisyUI remains the go-to Tailwind plugin for developers who want semantic class names. v5 brought Tailwind v4 compatibility and oklch-based themes. If you're building static sites or prefer CSS-only components, DaisyUI is hard to beat.</p>
<p>-&gt;<a href="https://daisyui.com">daisyui.com</a></p>
<h3>shadcn/ui - Copy-Paste Components</h3>
<p>The copy-paste model that launched a thousand forks. shadcn/ui gives you full code ownership of Radix + Tailwind components. Great if you want to customize everything, but be prepared to manage updates yourself.</p>
<p>-&gt;<a href="https://ui.shadcn.com">ui.shadcn.com</a></p>
<h2>Animation Libraries</h2>
<h3>Tailwind CSS Animate</h3>
<p>The official-feeling animation plugin for Tailwind CSS. Provides utility classes for common CSS animations - <code>animate-in</code>, <code>fade-in</code>, <code>slide-in-from-top</code>, <code>zoom-in</code>, etc. Used extensively by shadcn/ui and other libraries.</p>
<pre><code class="language-html">&lt;div class="animate-in fade-in slide-in-from-bottom-4 duration-500"&gt;
  Content appears with a smooth entrance
&lt;/div&gt;
</code></pre>
<p>In Tailwind v4, these integrate cleanly with the new <code>@source inline()</code> safelist pattern if you're consuming them from npm.</p>
<h3>Framer Motion</h3>
<p>Not Tailwind-specific, but Framer Motion remains the gold standard for React animations in 2026. Use it alongside Tailwind for complex gesture-driven and layout animations that CSS alone can't handle.</p>
<h3>Motion One</h3>
<p>A lightweight alternative to Framer Motion (~3.5KB) built on the Web Animations API. Perfect when you want smooth animations without the bundle weight. Works great with Tailwind's utility classes for initial styling.</p>
<h2>Typography &amp; Content</h2>
<h3>@tailwindcss/typography</h3>
<p>The official typography plugin for beautiful prose content. Essential for blogs, documentation, and content-heavy pages. v4 brought simplified configuration:</p>
<pre><code class="language-css">@plugin "@tailwindcss/typography";
</code></pre>
<p>Use the <code>prose</code> class to get beautiful defaults for Markdown-rendered content, with full dark mode support.</p>
<h3>Tailwind CSS Container Queries</h3>
<p>Container queries landed in all major browsers in 2024, and Tailwind v4 supports them natively with <code>@container</code> variants. This eliminates the need for third-party plugins - just use <code>@container</code> in your CSS or <code>@min-width</code> / <code>@max-width</code> in your Tailwind classes.</p>
<h2>Icon Libraries</h2>
<h3>Lucide React</h3>
<p>The community-maintained fork of Feather Icons, Lucide provides 1500+ beautiful SVG icons as React components. Tree-shakeable, consistent 24×24 grid, and perfect with Tailwind's <code>size-*</code> utilities:</p>
<pre><code class="language-tsx">import { Search, ArrowRight, Check } from "lucide-react";

&lt;Search className="size-5 text-base-content/60" /&gt;
</code></pre>
<h3>Heroicons</h3>
<p>Made by the Tailwind CSS team, Heroicons provides 300+ icons in outline, solid, and mini styles. Slightly smaller set than Lucide but with an extremely consistent visual language.</p>
<h3>Phosphor Icons</h3>
<p>If you need variety, Phosphor offers 9,000+ icons across 6 weight variations (thin, light, regular, bold, fill, duotone). The React package is tree-shakeable.</p>
<h2>Developer Tools</h2>
<h3>Tailwind CSS IntelliSense (VS Code)</h3>
<p>The official VS Code extension is essential. In 2026, it supports Tailwind v4's CSS-first configuration, providing autocomplete and hover previews for <code>@theme</code> values, custom utilities, and <code>@variant</code> definitions.</p>
<h3>Prettier Plugin for Tailwind CSS</h3>
<p>Automatically sorts your Tailwind utility classes in a consistent, readable order. With v4, the plugin understands the new class naming patterns and works seamlessly.</p>
<pre><code class="language-bash">pnpm add -D prettier-plugin-tailwindcss
</code></pre>
<h3>Tailwind Merge</h3>
<p>When building component libraries, <code>tailwind-merge</code> is essential for resolving class conflicts. It ensures that when a consumer passes <code>className="p-4"</code> to a component that already has <code>className="p-6"</code>, the consumer's class wins:</p>
<pre><code class="language-tsx">import { twMerge } from "tailwind-merge";

function Button({ className, ...props }) {
  return &lt;button className={twMerge("px-4 py-2 bg-blue-500", className)} {...props} /&gt;;
}
</code></pre>
<p>Ninna UI uses this internally via a <code>cn()</code> utility (clsx + tailwind-merge).</p>
<h2>Form Libraries</h2>
<h3>React Hook Form + Tailwind</h3>
<p>React Hook Form v8 remains the performance king for React forms. Pair it with Tailwind CSS components for a fast, accessible form experience:</p>
<pre><code class="language-tsx">import { useForm } from "react-hook-form";
import { Input, Field } from "@ninna-ui/forms";
import { Button } from "@ninna-ui/primitives";

function LoginForm() {
  const { register, handleSubmit } = useForm();
  return (
    &lt;form onSubmit={handleSubmit(onSubmit)}&gt;
      &lt;Field label="Email"&gt;
        &lt;Input {...register("email")} placeholder="you@example.com" /&gt;
      &lt;/Field&gt;
      &lt;Button type="submit" color="primary"&gt;Sign In&lt;/Button&gt;
    &lt;/form&gt;
  );
}
</code></pre>
<h3>Zod + Form Validation</h3>
<p>Zod continues to dominate TypeScript-first schema validation. Combined with React Hook Form's <code>zodResolver</code>, you get end-to-end type-safe forms with zero runtime overhead from the validation layer.</p>
<h2>Build Tools</h2>
<h3>@tailwindcss/vite</h3>
<p>The official Vite plugin for Tailwind v4. Zero-config - just add it to your Vite config and import Tailwind in CSS:</p>
<pre><code class="language-ts">import tailwindcss from "@tailwindcss/vite";

export default defineConfig({
  plugins: [tailwindcss()],
});
</code></pre>
<h3>@tailwindcss/postcss</h3>
<p>For Next.js and other PostCSS-based setups. Same zero-config approach as the Vite plugin.</p>
<h2>The 2026 Tailwind Stack</h2>
<p>Here's what a modern Tailwind CSS stack looks like in 2026:</p>
<table>
<thead>
<tr>
<th>Layer</th>
<th>Tool</th>
</tr>
</thead>
<tbody><tr>
<td><strong>Framework</strong></td>
<td>React 19 + Next.js 15 / Vite 7 / React Router v7</td>
</tr>
<tr>
<td><strong>Styling</strong></td>
<td>Tailwind CSS v4 (<code>@tailwindcss/vite</code> or <code>@tailwindcss/postcss</code>)</td>
</tr>
<tr>
<td><strong>Components</strong></td>
<td>Ninna UI (69 accessible components, CSS-only theming)</td>
</tr>
<tr>
<td><strong>Icons</strong></td>
<td>Lucide React (1500+ tree-shakeable icons)</td>
</tr>
<tr>
<td><strong>Typography</strong></td>
<td>@tailwindcss/typography</td>
</tr>
<tr>
<td><strong>Animation</strong></td>
<td>tailwindcss-animate + Framer Motion (when needed)</td>
</tr>
<tr>
<td><strong>Forms</strong></td>
<td>React Hook Form + Zod</td>
</tr>
<tr>
<td><strong>DX</strong></td>
<td>Tailwind IntelliSense + Prettier plugin + tailwind-merge</td>
</tr>
</tbody></table>
<p>This stack gives you:</p>
<ul>
<li><p><strong>Zero runtime theming</strong> (CSS custom properties)</p>
</li>
<li><p><strong>WCAG AA accessibility</strong> (Radix internals)</p>
</li>
<li><p><strong>Full type safety</strong> (TypeScript generics throughout)</p>
</li>
<li><p><strong>Sub-second builds</strong> (Lightning CSS engine)</p>
</li>
<li><p><strong>Tree-shakeable everything</strong> (ESM packages)</p>
</li>
</ul>
<p>-&gt; <a href="https://ninna-ui.dev/getting-started/installation">Try the full stack with Ninna UI</a></p>
]]></content:encoded></item></channel></rss>