Skip to main content

Tailwind v4 + shadcn/ui: Default SaaS Stack 2026

·StarterPick Team
Share:

Tailwind CSS v4 + shadcn/ui: The Default SaaS UI Stack 2026

The SaaS UI conversation ended in 2024. Tailwind CSS and shadcn/ui became the default — not by mandate, but by adoption. Walk through any popular SaaS boilerplate's package.json in 2026: Tailwind and shadcn/ui are there. ShipFast, Supastarter, MakerKit, Bedrock, next-forge — all of them.

Then Tailwind v4 shipped. The configuration model changed fundamentally. shadcn/ui migrated. Boilerplates updated. This guide explains what changed, why it matters, and what you need to know for new SaaS projects in 2026.

TL;DR

Tailwind CSS v4 moves configuration from tailwind.config.js (JavaScript) to globals.css (CSS). The @theme directive replaces the config file; OKLCH replaces HSL for colors; the build engine is 3.5x faster for full builds and 8x faster for incremental. shadcn/ui has migrated fully — new projects initialize with Tailwind v4 by default. For existing v3 projects, the migration is non-breaking with an automated upgrade tool. For new SaaS projects in 2026, v4 is the starting point.

Key Takeaways

  • CSS-first configuration: tailwind.config.js is gone — all config now lives in globals.css via @theme
  • OKLCH color space: Replaces HSL. More perceptually uniform, better for accessible dark mode palettes
  • Performance: 3.5x faster full builds, 8x faster incremental builds (measured in milliseconds, not seconds)
  • shadcn/ui v4 compatibility: Full support — npx shadcn@latest init initializes with Tailwind v4, React 19, and tw-animate-css
  • Migration: Automated — npx @tailwindcss/upgrade@next handles most of the conversion automatically
  • Boilerplate status: All major Next.js SaaS starters updated to Tailwind v4 as of Q1 2026

What Changed in Tailwind CSS v4

CSS-First Configuration

The biggest paradigm shift: Tailwind v4 removes tailwind.config.js entirely. Configuration moves into your CSS file.

Before (Tailwind v3):

// tailwind.config.js
module.exports = {
  content: ["./src/**/*.{ts,tsx}"],
  theme: {
    extend: {
      colors: {
        brand: {
          50: "#f0f9ff",
          500: "#3b82f6",
          900: "#1e3a5f",
        },
      },
      fontFamily: {
        sans: ["Inter", "sans-serif"],
      },
    },
  },
  plugins: [require("@tailwindcss/typography")],
};

After (Tailwind v4):

/* globals.css */
@import "tailwindcss";
@import "@tailwindcss/typography";

@theme {
  --color-brand-50: oklch(97% 0.02 230);
  --color-brand-500: oklch(60% 0.15 230);
  --color-brand-900: oklch(25% 0.08 230);

  --font-family-sans: "Inter", sans-serif;
}

That's the entire configuration. One CSS file, no JavaScript build config. The @import "tailwindcss" replaces the old @tailwind base; @tailwind components; @tailwind utilities directives.

The @theme Directive

@theme is where you define your design tokens — colors, fonts, spacing, breakpoints. Everything you'd put in theme.extend in the config file:

@theme {
  /* Colors */
  --color-primary: oklch(60% 0.20 250);
  --color-primary-foreground: oklch(98% 0.01 250);
  --color-secondary: oklch(95% 0.02 250);
  --color-destructive: oklch(55% 0.22 25);

  /* Spacing scale extension */
  --spacing-18: 4.5rem;
  --spacing-88: 22rem;

  /* Typography */
  --font-family-display: "Cal Sans", "Inter", sans-serif;

  /* Breakpoints */
  --breakpoint-3xl: 1920px;
}

These variables become Tailwind utilities automatically:

  • --color-primarybg-primary, text-primary, border-primary
  • --spacing-18p-18, m-18, w-18
  • --font-family-displayfont-display

OKLCH Colors

Tailwind v4 adopts OKLCH as the color model. OKLCH is perceptually uniform — equal numeric steps in lightness look equal to the human eye (HSL doesn't guarantee this).

/* HSL (Tailwind v3 shadcn/ui) */
:root {
  --background: 0 0% 100%;           /* hsl(0, 0%, 100%) = white */
  --foreground: 222.2 84% 4.9%;      /* hsl(222, 84%, 5%) = near black */
  --primary: 221.2 83.2% 53.3%;      /* hsl(221, 83%, 53%) = blue */
}

/* OKLCH (Tailwind v4 shadcn/ui) */
:root {
  --background: oklch(1 0 0);         /* white */
  --foreground: oklch(0.14 0.04 250); /* near black, slight blue tint */
  --primary: oklch(0.60 0.20 250);    /* blue */
}

Why this matters for SaaS dark mode:

/* OKLCH dark mode is more predictable */
.dark {
  /* Lightness values invert cleanly */
  --background: oklch(0.10 0 0);     /* dark background */
  --foreground: oklch(0.97 0 0);     /* light text */
  --primary: oklch(0.70 0.18 250);   /* slightly lighter blue (not just inverted HSL) */
}

With HSL, generating accessible dark mode colors requires manual adjustment. With OKLCH, the perceptual uniformity means you can generate light/dark pairs more systematically.


shadcn/ui in 2026: The Migration

shadcn/ui migrated fully to Tailwind v4 in early 2026. New projects initialized with npx shadcn@latest init get:

✓ Tailwind CSS v4
✓ React 19 compatibility
✓ tw-animate-css (replaces tailwindcss-animate)
✓ OKLCH colors (in globals.css, not tailwind.config.js)
✓ data-slot attributes on every component
✓ Updated component registry (all components updated)

Initializing in 2026

# Create a new Next.js project
npx create-next-app@latest my-saas --typescript --tailwind --app

# Initialize shadcn/ui (automatically detects Tailwind v4)
npx shadcn@latest init

The CLI detects Tailwind v4 in your project and generates the appropriate v4 configuration. You don't manually choose v4 vs v3 — it reads your installed version.

What the Init Generates

/* globals.css — generated by shadcn/ui init for Tailwind v4 */
@import "tailwindcss";
@import "tw-animate-css";

@custom-variant dark (&:is(.dark *));

@theme inline {
  --radius-sm: calc(var(--radius) - 4px);
  --radius-md: calc(var(--radius) - 2px);
  --radius-lg: var(--radius);
  --radius-xl: calc(var(--radius) + 4px);

  --color-background: var(--background);
  --color-foreground: var(--foreground);
  --color-primary: var(--primary);
  --color-primary-foreground: var(--primary-foreground);
  /* ... all shadcn tokens */
}

:root {
  --radius: 0.625rem;
  --background: oklch(1 0 0);
  --foreground: oklch(0.145 0 0);
  --primary: oklch(0.205 0 0);
  --primary-foreground: oklch(0.985 0 0);
  /* ... */
}

.dark {
  --background: oklch(0.145 0 0);
  --foreground: oklch(0.985 0 0);
  --primary: oklch(0.922 0 0);
  --primary-foreground: oklch(0.205 0 0);
  /* ... */
}

tw-animate-css: The Animation Change

The old tailwindcss-animate plugin is deprecated. Tailwind v4 replaces it with tw-animate-css — a pure CSS animation library that doesn't require a Tailwind plugin.

/* Old: tailwindcss-animate (v3) */
/* In tailwind.config.js: require("tailwindcss-animate") */
/* Used: animate-in, animate-out, fade-in-0, zoom-in-95 */

/* New: tw-animate-css (v4) */
@import "tw-animate-css";
/* Same classes still work — fully backward compatible */

For most SaaS apps, this change is invisible — animate-in, fade-in-0, slide-in-from-top-2 all still work. The import location moves from the config file to CSS.


Setting Up a SaaS Project with Tailwind v4 + shadcn/ui

Full setup from scratch:

# 1. Create Next.js app
npx create-next-app@latest my-saas \
  --typescript \
  --tailwind \
  --eslint \
  --app \
  --src-dir \
  --import-alias "@/*"

# 2. Initialize shadcn/ui
cd my-saas
npx shadcn@latest init

# Select: Default style, neutral base color, CSS variables: yes

# 3. Add components
npx shadcn@latest add button card input label badge

# 4. Add your brand colors to globals.css

Adding Brand Colors (v4 Pattern)

/* src/app/globals.css */
@import "tailwindcss";
@import "tw-animate-css";

@custom-variant dark (&:is(.dark *));

/* Override shadcn tokens with your brand */
:root {
  --primary: oklch(0.55 0.22 250);        /* your brand blue */
  --primary-foreground: oklch(0.98 0 0);   /* white text on primary */
  --radius: 0.5rem;                         /* your border radius */
}

.dark {
  --primary: oklch(0.70 0.18 250);         /* lighter for dark mode */
  --primary-foreground: oklch(0.10 0 0);   /* dark text on primary */
}

That's all you need to brand the entire shadcn/ui component library. Every button, badge, and link picks up --primary automatically.


Performance: The Build Speed Numbers

Tailwind v4's new Rust-based engine (Oxide) delivers:

ScenarioTailwind v3Tailwind v4Improvement
Full build~1,200ms~340ms3.5x faster
Incremental build~150ms~18ms8x faster
Cold start (CI)~2,100ms~580ms3.6x faster

For development, incremental rebuilds at 18ms are effectively instantaneous. Tailwind no longer feels like it's rebuilding on every save.


Migrating Existing SaaS Projects from v3

If you have an existing boilerplate on Tailwind v3:

# Run the automated upgrade tool
npx @tailwindcss/upgrade@next

# What it does:
# ✓ Installs Tailwind v4
# ✓ Removes tailwind.config.js
# ✓ Creates CSS configuration in globals.css
# ✓ Converts HSL colors to OKLCH
# ✓ Replaces tailwindcss-animate with tw-animate-css
# ✓ Updates shadcn/ui components (if detected)

Migration notes for SaaS codebases:

  1. Custom color tokens — If you've defined custom colors in tailwind.config.js, they're moved to @theme in CSS. The class names (bg-brand-500) remain unchanged.

  2. JIT content paths — The content array in tailwind.config.js is automatically inferred from your project structure in v4. You don't need to configure it.

  3. Plugin compatibility — Most popular Tailwind plugins have v4 versions. @tailwindcss/typography is the one you're most likely using — it's updated and imported via CSS (@import "@tailwindcss/typography") instead of the config file.

  4. shadcn/ui components — Run npx shadcn@latest diff to see which components have updates. Re-adding updated components (npx shadcn@latest add button) pulls the latest v4-compatible versions.


Why This Combination Won

Tailwind v4 + shadcn/ui won the SaaS UI battle for practical reasons:

No runtime overhead: Both are compile-time solutions. Tailwind generates static CSS. shadcn/ui copies components into your repo. Zero runtime cost.

Full ownership: shadcn/ui isn't a component library you import — it's components you own. Customize any component without fighting a library's API. Update when you want, not when the library releases.

Design system without the work: The combination gives you a consistent design system (shared tokens, consistent spacing, matching dark mode) without hiring a designer. The default aesthetic is professional enough to ship.

Ecosystem momentum: In 2026, every Next.js resource — YouTube tutorials, GitHub templates, Stack Overflow answers — assumes Tailwind + shadcn/ui. The shared vocabulary makes onboarding new developers faster.

The question for SaaS builders isn't "should I use Tailwind + shadcn/ui?" It's "which boilerplate that already has it configured should I start with?"


SaaS Boilerplate Tailwind v4 Support Status

As of March 2026, here's where major SaaS boilerplates stand:

BoilerplateTailwind v4shadcn/ui v4Status
next-forgeUpdated Q1 2026
ShipFastUpdated Q1 2026
SupastarterUpdated Q1 2026
MakerKitUpdated Q1 2026
BedrockUpdated Q1 2026
SvelteshipVia shadcn-svelteUpdated (shadcn-svelte v4)
create-t3-appUpdated Q1 2026

All major Next.js SaaS starters shipped Tailwind v4 updates in Q1 2026. When evaluating boilerplates, checking for v4 support is now a baseline — a starter still on v3 is a maintenance warning signal.


The Component Ecosystem in 2026

shadcn/ui's model — copy components into your repo — spawned an ecosystem of pre-built block libraries:

shadcn/ui blocks — Official pre-built page sections (dashboard layouts, login pages, settings pages). Added to the shadcn/ui registry in 2025, now includes 30+ production-ready blocks.

shadcnblocks.com — Community-maintained shadcn/ui sections. Marketing page heroes, feature sections, pricing tables, FAQs. Free tier covers the most-used components.

21st.dev — AI-generated shadcn/ui components. Describe what you want, get a component you can copy into your repo. Quality varies but useful for one-off custom components.

For SaaS builders, the practical workflow: start with next-forge or another boilerplate for the dashboard structure, use shadcn/ui blocks for marketing page sections, and copy custom components from shadcnblocks or 21st.dev as needed. You build your entire UI without writing component primitives from scratch.

Browse all boilerplates with shadcn/ui on StarterPick. Related: comparing shadcn/ui vs Radix vs Headless UI and why SaaS boilerplates choose Next.js.

Theming at Scale: Design Tokens That Don't Break

The OKLCH color model that Tailwind v4 and shadcn/ui adopt is not just a technical detail — it has a practical impact on how you maintain dark mode and brand theming across a growing component library.

The problem with HSL (the v3 approach): HSL's lightness channel doesn't correspond to perceived lightness uniformly across hues. A blue at HSL lightness 50% looks darker than a yellow at the same lightness value. This means hand-tuning color pairs for dark mode requires many manual adjustments to achieve perceptual consistency.

OKLCH's lightness channel is perceptually uniform. Moving from oklch(0.60 0.20 250) (a medium-dark blue) to oklch(0.70 0.18 250) in dark mode gives you a reliably lighter version that looks equally bright across different monitor calibrations. The chroma value (0.20 and 0.18) can be slightly reduced in dark mode to prevent colors from looking oversaturated on backlit displays — a common dark mode design problem that OKLCH makes easier to control systematically.

For SaaS products with multiple brand color palettes (white-label products, multiple themes), this perceptual uniformity means you can generate accessible color palettes programmatically rather than designing each shade manually. Tools like Tailwind's new color generation utilities and oklch.com's picker work with the Tailwind v4 @theme system to generate complete palettes from a single hue value.

When to Upgrade Existing Projects

The automated upgrade tool (npx @tailwindcss/upgrade@next) handles most of the mechanical migration, but there are scenarios where manual review is worth the time investment.

If your project has more than 50 custom Tailwind classes defined in the config file, verify each one was correctly migrated to the @theme directive. The upgrade tool handles standard extensions well but can struggle with complex plugin-based customizations or unusual config structures.

If you use many shadcn/ui components with custom styling overrides (className prop additions), verify those overrides still work after migration. Tailwind v4's utility class naming is mostly backward-compatible, but some utilities changed behavior or were renamed. Run your component tests after upgrading to surface any broken styles.

The best time for existing projects to upgrade: during a planned maintenance sprint rather than as a side effect of feature development. A focused upgrade effort with proper testing takes a day for most SaaS projects. Doing it incrementally alongside feature work makes it harder to attribute visual regressions to the upgrade vs the new feature code.


Browse all boilerplates with shadcn/ui on StarterPick.

See the shadcn vs Radix vs Headless UI comparison for when to consider alternatives to shadcn/ui.

Review best SaaS boilerplates for 2026 — all of which now use Tailwind v4 + shadcn/ui as their UI foundation.

The SaaS Boilerplate Matrix (Free PDF)

20+ SaaS starters compared: pricing, tech stack, auth, payments, and what you actually ship with. Updated monthly. Used by 150+ founders.

Join 150+ SaaS founders. Unsubscribe in one click.