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 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.