Laden...
Laden...
sapan.dev runs on Tailwind v4 — no `tailwind.config.js`, the design tokens live in CSS, and the build is dramatically faster. Notes from the migration off v3 and what the new architecture actually changes day-to-day.
When I rebuilt sapan.dev, I jumped straight to Tailwind v4 without a v3 phase. The thing that surprised me most: there is no `tailwind.config.js` at all anymore. The design tokens are CSS custom properties declared in `@theme`, and they become utilities automatically. After years of bouncing between a `tailwind.config.js` and a `globals.css` to keep tokens in sync, this single-source-of-truth feels like a meaningful simplification.
Tailwind CSS v4 is not a minor update — it is a ground-up rewrite. The configuration moves from JavaScript to CSS, the build engine is rewritten in Rust (via Lightning CSS), and many conventions that felt essential in v3 are now replaced with better defaults.
In v3, all configuration lived in tailwind.config.js. In v4, configuration lives in your CSS file using @theme. This is a fundamental shift that makes your design tokens real CSS custom properties from the start.
/* v4 configuration in CSS */
@import "tailwindcss";
@theme {
--font-display: "Inter", sans-serif;
--color-brand: oklch(62% 0.2 240);
--spacing-18: 4.5rem;
--radius-card: 1rem;
}Info
Every @theme variable is automatically available as a utility class. --color-brand becomes bg-brand, text-brand, border-brand — no plugin required.
Tailwind v4 uses CSS cascade layers natively, which means Tailwind utilities no longer fight with your custom CSS for specificity. Base styles, components, and utilities are in separate layers, so override order is predictable and explicit.
/* Tailwind internally uses layers */
@layer base { ... }
@layer components { ... }
@layer utilities { ... }
/* Your custom component — always wins over utilities */
@layer components {
.card {
background: white;
border-radius: var(--radius-card);
}
}v4 introduces a new set of utilities that were either impossible or impractical in v3. These include native container queries, data-* attribute variants, and arbitrary value support that actually understands CSS functions.
Tailwind provides an official migration guide and codemod. The biggest changes to watch for are the removal of the JIT toggle (always on in v4), the configuration format change, and renamed utilities.
# Run the official upgrade codemod
npx @tailwindcss/upgrade@next
# Or install manually
npm install tailwindcss@next @tailwindcss/viteWaarschuwing
The shadow-sm, rounded-sm, and blur-sm utilities now map to larger values than in v3. Test your UI after migrating — visual regressions in these areas are common.
The Lightning CSS-powered engine is dramatically faster. Full rebuilds that took 400ms in v3 now complete in under 50ms. Incremental rebuilds are nearly instant. For large projects, this meaningfully improves developer experience.
On sapan.dev with v4, the design system is entirely in CSS — `--color-primary`, `--color-success`, the dark-mode swap pairs (e.g., `tw-alv tw-li`) — and there is no JavaScript build step for tokens. The `data-[state=open]` variants made the popovers and sheets cleaner. Native container queries with `@lg:flex-row` removed a couple of plugin dependencies. Worth migrating if you are starting fresh; the codemod handles most of the upgrade if you have an existing v3 codebase, but expect to do a visual regression pass afterwards (the renamed shadow/rounded/blur utilities will catch you out).
Meer in CSS
Notes from rebuilding sapan.dev with the View Transitions API for navigation across 16 locales. Replaced an entire Framer Motion orchestration layer with a CSS file, found one annoying flash on RTL Arabic, and walked away with a much smaller bundle.
Modern CSS features I now reach for in every project — and the specific moments on the Templately admin and sapan.dev where each one replaced a chunk of JavaScript or some BEM gymnastics that had been there for years.
sapan.dev's design tokens are oklch all the way down. The brand color is one variable; every shade, hover, and disabled state derives from it programmatically. Notes on what oklch and color-mix actually buy you in a design system.