Upgrading to Tailwind v4
March 20, 2025

This was kind of a pain, but here's how I did it.
Start in clean branch. (obvi)
pnpm dlx @tailwindcss/upgrade
pnpm add clsx@latest
pnpm add tailwind-merge@latest
pnpm remove tailwind-animate
pnpm add tw-animate-css -DAdd @import 'tw-animate-css'; to globals.css after @import 'tailwindcss';
@import 'tailwindcss';
@import 'tw-animate-css';Move fonts to @theme inline.
/* https://tailwindcss.com/docs/theme#referencing-other-variables */
@theme inline {
--font-sans: var(--font-inter), Arial, Helvetica, sans-serif;
}Add button CSS.
@layer base {
button:not(:disabled),
[role="button"]:not(:disabled) {
cursor: pointer;
}
}Port your "components" from v3 config to v4 utility classes.
@utility my-display-title {
font-weight: 600;
font-size: 24px;
line-height: 32px;
}Follow shadcn's recommendation on CSS variables. Move all your CSS vars to :root and .dark respectively.
:root {
--background: 0 0% 100%;
}
.dark {
--background: 240 10% 3.9%;
}
@theme {
--color-background: hsl(var(--background));
}Then wrap them in hsl() and remove hsl() from its usage.
:root {
--background: hsl(0 0% 100%);
}
.dark {
--background: hsl(240 10% 3.9%);
}
@theme {
--color-background: var(--background);
}Then move the entire theme to inline because Tailwind says you have to do this to reference other variables.
@theme inline {
--color-background: var(--background);
}Lastly, replace all h-* w-* with size-*. This is easy if you have prettier and prettier-plugin-tailwindcss installed. Since the Tailwind migration ran in the first step, your class names might not be in order anymore. Run prettier --write ./src and let Prettier sort everything. It will put height first, width second. Then run a regex find and replace:
# Search: h-(\d+)\s+w-\1
# Replace: size-$1At this point you should be completely migrated to Tailwind v4 and prepped for shadcn updates. Commit into main and call it a day.
- jonkwheeler