Jean Galea

AI, Investing, Health, and Building Businesses

  • Start Here
  • Guides
    • Beginner’s Guide to Investing
    • Cryptocurrencies
    • Stocks
    • P2P Lending
    • Real Estate
  • Blog
  • My Story
  • Projects
  • Community
  • AI Consultancy
  • Search

Tailwind, shadcn/ui, and the New Design-System Meta

Published: June 13, 2026Leave a Comment

A designer working at a clean modern desk

This is part of an ongoing series I am writing as I work my way through the modern web stack from a WordPress developer’s perspective. The series is aimed at WordPress veterans who, like me, have built things on the web for years and feel quietly behind the curve. The goal is broad literacy, not deep mastery. By the end you should be able to read any modern stack list and know what each piece is doing.

Each post comes with an audio companion (10-15 minutes, generated via NotebookLM) for gym or commute listening. Press play below if that suits you better than reading.

Hook

For most of my WordPress career, “styling” meant a style.css file in the theme directory, maybe organised into a few partials, possibly compiled from SCSS, with a Genesis or Underscores starter underneath. CSS classes had semantic names: .site-header, .entry-content, .widget-area. The mental model was straight out of 2010: name elements by their role, style each one in a stylesheet, hope you remembered which class belonged where.

Then I opened a modern Next.js codebase and every single HTML element looked like this:

<span id="cb1-1"><a href="#cb1-1" aria-hidden="true" tabindex="-1"></a><span class="dt"><</span><span class="kw">div</span><span class="ot"> className</span><span class="op">=</span><span class="st">"flex items-center justify-between rounded-lg border bg-card px-4 py-3 text-sm shadow-sm"</span><span class="dt">></span></span>

No semantic class names. No external stylesheet. Just a wall of short utility classes inside the markup. My first reaction was something between confusion and revulsion. This is what they meant when they said modern frontend was bad, surely.

I was wrong. Tailwind has won, decisively, for reasons that take a while to appreciate from the outside. And then on top of Tailwind there is shadcn/ui, which is doing something even weirder and even more effective. This module is the translation of why and how.

Core Concept

Tailwind CSS is a utility-first CSS framework. Instead of writing class names that describe what something is (button-primary, nav-item), you compose styles inline by writing class names that describe what something does (px-4 py-2 bg-blue-500 rounded text-white).

The advantages take a minute to surface.

You stop naming things. Every WordPress theme developer has spent hours arguing with themselves about class names. .cta, .action, .primary-button, .button-primary, .btn-cta. With Tailwind the question never arises. You compose the styles directly.

The stylesheet stops growing. Traditional CSS files balloon as features are added, with old rules left in case something still uses them. Tailwind’s stylesheet is the same size whether you have ten components or ten thousand, because every class is reused across the codebase. The build step also strips unused classes, so production CSS is tiny.

Consistency comes from the design tokens. You configure your design system once (tailwind.config.ts): the colour palette, spacing scale, type scale, breakpoints. Then every utility class is constrained to those tokens. Designers and developers literally cannot drift from the system; the framework will not let them.

Components stay self-contained. A Tailwind-styled component is fully described by its own JSX. You can read its appearance from the markup alone. No need to open a stylesheet to find out what .entry-meta does in this particular theme.

The trade-off is that the markup looks busy. That is the right trade-off for modern component-based development, where you read code in the context of one component at a time rather than across the whole site.

Shadcn/ui

shadcn/ui is the layer that built on top of Tailwind to solve the “component primitives” problem.

Most design systems shipped as packages you installed (Material UI, Chakra, MUI, Ant Design). You imported their components, customised through props, and lived with their API forever. The customisation always hit a ceiling. The bundle size always grew.

shadcn/ui took a different approach. It is not a package. It is a CLI that copies the component source code directly into your repo. You run npx shadcn add button and a Button component appears in src/components/ui/button.tsx. You can edit it however you like. There is no library to update; the code is yours.

The components are built on Radix UI (an accessible-component primitive library) and styled with Tailwind. They look good by default, follow accessibility best practices, and become customisable by editing the code. This combination has eaten the React component-library market faster than almost anything else in the last three years.

The WordPress Analogue

Mental model: Tailwind is to CSS what Gutenberg’s block library is to page-builder shortcodes — opinionated primitives that compose into anything. shadcn/ui is to React components what a starter theme is to a custom WordPress theme: a working template you customise rather than a library you call.

The deeper analogy: WordPress had this debate fifteen years ago. Was it better to write semantic CSS classes and let the stylesheet describe the design, or to use utility classes (the way Bootstrap did) and compose inline? WordPress culture chose semantic. React culture chose utility. Both work; the React choice happened to dovetail with component-based development in a way that Bootstrap on top of WP themes never quite did.

The Landscape

The main styling approaches you will meet in modern React projects:

Approach Style location Strengths Trade-offs
Tailwind CSS Inline className utilities Tiny CSS bundle, consistency, no naming Verbose markup, learning curve
CSS Modules Co-located CSS files scoped to component Familiar CSS syntax, automatic scoping More files, harder to share design tokens
CSS-in-JS (styled-components, Emotion) Inside JS files Dynamic styling, theme support Runtime overhead, increasingly unpopular
Vanilla CSS Old-school stylesheets No build complexity, simplest model Drift, hard to scale on teams
Tailwind + shadcn/ui Tailwind utilities + customisable copy-in components Default modern setup; ships fast Tailwind verbosity carries through
Component libraries (Material UI, Chakra) Library-provided components, theme system Get a complete design system fast Customisation hits walls, larger bundles

For 2026, the default is Tailwind + shadcn/ui for almost any new React or Next.js project. The combination is so dominant that “starter kits” usually mean “Next.js + Tailwind + shadcn/ui + maybe Drizzle and Supabase.”

Tailwind 4, which shipped in late 2024, removed the configuration JS file and now reads design tokens from CSS itself. This shifts the developer experience subtly; older guides reference tailwind.config.js but the modern setup is more CSS-native.

What This Changes for WordPress People

Three practical wins.

The first is custom Gutenberg blocks become more tractable. WordPress’s block editor is built on React. Tailwind works inside Gutenberg blocks just fine. If you have ever shipped a custom block with bespoke CSS, switching to Tailwind reduces the styling work dramatically, and the resulting blocks look more consistent with the rest of the modern web.

The second is design hand-offs improve. When a designer hands you a Figma file with spacing tokens (4, 8, 12, 16, 24…) and a colour palette, you can map those directly to Tailwind’s tailwind.config and the design system stays consistent across implementation. WordPress themes traditionally drift from designs because the implementation invents its own classes.

The third is the AI dev productivity story improves. AI agents are extremely good at writing Tailwind because the class names are short, the patterns are well-documented, and the constraints prevent the AI from hallucinating styles. Hand an agent a Figma file and ask for the implementation in Tailwind + shadcn/ui, and the output is usually 90% right. Same agent producing WordPress theme CSS produces inconsistent, hard-to-review output.

Watch Out

A few traps.

Tailwind’s verbosity is real. A complex component can have classes that wrap to three lines. Use the @apply directive for genuinely reusable patterns (a button style used across the site), but resist the temptation to abstract every component into a custom class. The verbosity is the price of the consistency and bundle size.

Dark mode is built in but needs setup. Tailwind has a dark: variant that you can apply to any class. To make dark mode work end-to-end, you also need a colour palette designed for both modes and a toggle that adds/removes the dark class on the root element. The mechanism is simple; the design work is not.

shadcn/ui components are your code. Updates do not come as pnpm update. To get new shadcn versions of a component, you re-run the CLI command and accept the new copy. This is the trade-off for the “code lives in your repo” model. Track which components you have copied and when.

Mixing styling approaches is painful. A codebase with half Tailwind, half CSS Modules, half styled-components becomes incoherent fast. Pick one approach per project and stay consistent.

The “Tailwind looks ugly” reaction is real but passes. New developers see a Tailwind component and recoil. After two weeks of writing Tailwind, the markup starts to read normally and the trade-off becomes obvious. Push through the first two weeks before deciding.

Going Deeper

If you want to graduate from “I can recognise Tailwind” to “I can write it productively,” a few resources.

YouTube, gym or commute friendly:

  • “Tailwind CSS in 100 Seconds” by Fireship, then “Why I use Tailwind for everything” by Theo (t3.gg, ~20 min).
  • “shadcn/ui tutorial” on the shadcn channel (~30 min). The CLI workflow is unusual enough that watching it once is worth more than reading about it.

Official docs worth bookmarking:

  • Tailwind CSS docs. The “Utility-first” introduction is the best argument for the approach. Read it before you decide whether you hate Tailwind.
  • shadcn/ui docs. Browse the component gallery; you will recognise the design language across half the modern web.
  • Radix UI primitives. The accessibility-first component primitives shadcn/ui is built on. Worth knowing if you ever build custom interactive components.

For the resource side of this, which copy-paste component libraries and which AI-coder tooling actually feed shadcn into your build, I wrote a companion piece: Why AI-Generated UI Looks Generic (and How to Fix It).

Next post in the series ties WordPress back into the modern stack: headless WordPress, what it actually is, when it makes sense, and how to think about hybrid CMS-plus-modern-frontend projects.

Related

Why AI-Generated UI Looks Generic (and How to Fix It)
Why AI-Generated UI Looks Generic (and How to Fix It)
A Comprehensive Guide to Malta’s 5% Effective Corporate Tax Rate
I Own Two Mazdas. The New CX-5 Is Why I Won’t Buy a Third.
Building a NAS Backup System (With Extras)
Getting an Online Extranjeria Appointment in Spain
The Best European Corporate and Personal Tax Structures in 2026

Filed under: General

About Jean Galea

I build things on the internet and write about AI, investing, health, and how to live well. Founder of AgentVania and the Good Life Collective.

Leave a Reply Cancel reply

Thanks for choosing to leave a comment. Please keep in mind that all comments are moderated according to our comment policy, and your email address will NOT be published. Please Do NOT use keywords or links in the name field.

Latest Padel Match

Jean Galea

Investor | Dad | Global Citizen | Athlete

Follow @jeangalea

  • My Padel Journey
  • Affiliate Disclaimer
  • Cookies
  • Contact

Copyright © 2006 - 2026