Tailwind v4 + shadcn/ui: Default SaaS Stack 2026
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.jsis gone — all config now lives inglobals.cssvia@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 initinitializes with Tailwind v4, React 19, andtw-animate-css - Migration: Automated —
npx @tailwindcss/upgrade@nexthandles 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-primary→bg-primary,text-primary,border-primary--spacing-18→p-18,m-18,w-18--font-family-display→font-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:
| Scenario | Tailwind v3 | Tailwind v4 | Improvement |
|---|---|---|---|
| Full build | ~1,200ms | ~340ms | 3.5x faster |
| Incremental build | ~150ms | ~18ms | 8x faster |
| Cold start (CI) | ~2,100ms | ~580ms | 3.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:
-
Custom color tokens — If you've defined custom colors in
tailwind.config.js, they're moved to@themein CSS. The class names (bg-brand-500) remain unchanged. -
JIT content paths — The
contentarray in tailwind.config.js is automatically inferred from your project structure in v4. You don't need to configure it. -
Plugin compatibility — Most popular Tailwind plugins have v4 versions.
@tailwindcss/typographyis the one you're most likely using — it's updated and imported via CSS (@import "@tailwindcss/typography") instead of the config file. -
shadcn/ui components — Run
npx shadcn@latest diffto 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:
| Boilerplate | Tailwind v4 | shadcn/ui v4 | Status |
|---|---|---|---|
| next-forge | ✅ | ✅ | Updated Q1 2026 |
| ShipFast | ✅ | ✅ | Updated Q1 2026 |
| Supastarter | ✅ | ✅ | Updated Q1 2026 |
| MakerKit | ✅ | ✅ | Updated Q1 2026 |
| Bedrock | ✅ | ✅ | Updated Q1 2026 |
| Svelteship | ✅ | Via shadcn-svelte | Updated (shadcn-svelte v4) |
| create-t3-app | ✅ | ✅ | Updated 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 Mantine vs SaaS UI and the complete Next.js SaaS tech stack guide.