The Dev Log › Tips & Cheat Codes
Tailwind CSS v4 Tips for Building UI Faster
By Jezer Niel Blanca, Full Stack Developer ·
·
6 min read
The Tailwind v4 tips I use daily: CSS-first theme tokens, @source, the renamed utilities that trip up upgrades, container queries, modern variants and custom utilities.
Tailwind CSS v4 changed more than a version number. Configuration moved into CSS, a lot of utilities were renamed, and several features that used to need plugins are now built in. If you learned Tailwind on v3, some of your muscle memory now produces the wrong result, and some great new features are easy to miss. These are the v4 tips I use constantly to build interfaces faster in Laravel and Vue projects, along with the renames that trip people up during upgrades.
Configure Your Design System in CSS
The biggest shift in v4 is that your theme lives in your stylesheet. There's no tailwind.config.js to maintain for most projects. You import Tailwind and define design tokens with the @theme directive:
@import "tailwindcss";
@theme {
--color-brand-50: oklch(0.97 0.02 270);
--color-brand-500: oklch(0.58 0.2 270);
--color-brand-700: oklch(0.45 0.18 270);
--font-display: "Inter", ui-sans-serif, system-ui, sans-serif;
--breakpoint-3xl: 120rem;
}
Each variable automatically generates utilities. --color-brand-500 gives you bg-brand-500, text-brand-500, border-brand-500 and the rest. --font-display gives you font-display, and --breakpoint-3xl gives you a 3xl: variant.
Your Tokens Are Real CSS Variables
Because theme values are CSS custom properties, you can use them anywhere, including inline styles, third-party components and charts. In utilities, v4 has a shorthand for referencing a variable in an arbitrary value:
<div class="bg-(--color-brand-500) p-4">Uses the brand token directly</div>
That parentheses syntax replaces the longer bg-[var(--color-brand-500)] form from v3.
Tell Tailwind Where to Look
Tailwind v4 detects your source files automatically and skips anything in .gitignore. Most Laravel projects work out of the box. When classes live somewhere it can't see, such as a package in vendor, add the path with @source:
@import "tailwindcss";
@source "../../vendor/some-vendor/some-package/resources/views";
If classes are silently missing in production, a missing @source is the first thing I check.
Never Build Class Names Dynamically
This isn't new, but it's still the most common cause of missing styles. Tailwind scans your files as plain text, so it can't see classes you construct at runtime:
// Tailwind can't find these classes
const classes = `bg-${color}-500`
// Tailwind can find these, because the full class names appear in the code
const colorClasses = {
success: 'bg-emerald-500',
danger: 'bg-rose-500',
} as const
Map values to complete class names and the scanner picks them all up.
Know the Renamed Utilities
Several v3 utilities were renamed in v4 to make the scale more consistent. These catch almost everyone during an upgrade:
shadow-sm became shadow-xs, and plain shadow became shadow-sm.
rounded-sm became rounded-xs, and plain rounded became rounded-sm.
blur-sm became blur-xs, and plain blur became blur-sm.
outline-none became outline-hidden, because outline-none now really sets outline-style: none.
bg-gradient-to-r became bg-linear-to-r.
- The default
ring width changed from 3px to 1px, so use ring-3 if you want the old look.
The official upgrade tool handles most of these automatically, but it's worth knowing them so hand-written classes come out right.
When something looks slightly smaller or flatter than you expected after an upgrade, check the renamed shadow, radius and ring utilities first.
Built-in Features That Used to Need Plugins
Some of my favourite v4 improvements are features that simply exist now.
Container Queries
Components can respond to the size of their container rather than the viewport. That makes cards and widgets genuinely reusable in sidebars, grids and modals:
<div class="@container">
<div class="flex flex-col gap-4 @md:flex-row @md:items-center">
<img class="size-16 rounded-xl" src="/avatar.jpg" alt="Profile photo">
<p class="text-sm @md:text-base">This layout adapts to its container width.</p>
</div>
</div>
Modern Variants
A few variants I use all the time:
not-* styles an element when a condition is false, like not-last:border-b for dividers between list items.
starting: sets initial styles for enter transitions, so elements can fade in when they appear without JavaScript.
inert: styles elements with the inert attribute, handy for disabled sections of a form.
in-* styles an element based on any ancestor's state, similar to group-* but without adding a group class.
<ul>
<li class="py-3 not-last:border-b border-zinc-200">First item</li>
<li class="py-3 not-last:border-b border-zinc-200">Last item has no border</li>
</ul>
Size and Field Sizing
size-10 sets width and height together, which I use for icons and avatars constantly. And field-sizing-content makes a textarea grow with its content, no JavaScript required.
Dark Mode and Custom Variants
By default, the dark: variant follows the user's operating system preference. If your site has a manual theme toggle that adds a dark class to the HTML element, override the variant in CSS:
@custom-variant dark (&:where(.dark, .dark *));
Now dark:bg-zinc-900 responds to your class rather than the system setting.
Custom Utilities
For a small utility you use everywhere, define it with @utility instead of reaching for @apply in random components:
@utility content-auto {
content-visibility: auto;
}
It works with every variant, so md:content-auto and hover:content-auto just work.
Using Tailwind Inside Vue Components
When you write a <style> block in a Vue single-file component and use @apply or theme variables there, the block needs to know about your main stylesheet. Add @reference at the top:
<style scoped>
@reference "../../css/app.css";
.card-title {
@apply text-lg font-semibold text-brand-700;
}
</style>
That said, I rarely need this. Keeping utilities in the template and extracting repeated patterns into Vue components is almost always cleaner than @apply.
Speed Habits Beyond the Framework
A few workflow habits make the biggest difference to how fast I build UI:
- Use the official editor extension for autocomplete and hover previews of generated CSS.
- Sort classes automatically with the official Prettier plugin, so diffs stay readable.
- Use
gap instead of margins between flex and grid children.
- Build mobile first, then add
md: and lg: overrides.
Wrapping up
Tailwind v4 rewards a small amount of relearning: define tokens with @theme, use @source for unusual paths, learn the renamed shadow, radius and ring utilities, and lean on built-in container queries and modern variants. Do that and you'll build interfaces faster with less custom CSS than before. If you want a fast, polished interface for your product, I'd love to build it with you and my team.
Tags: Tailwind CSS, CSS, Frontend, UI