Part 1 of this series covered fifteen utilities most developers walk right past. The response was clear: there are more. Tailwind CSS v4 landed with a CSS-first configuration model, a modernized color palette, and a surprisingly large surface area of new utilities and variants. Most tutorials cover the big stuff — the @theme block, container queries, 3D transforms. This post covers the twenty that get ignored.
All of these are real, stable utilities in the current v4 release. Verified against the official docs. No made-up class names.
Shadow Utilities
1. inset-shadow-*
Tailwind v4 ships a dedicated set of inset shadow utilities that work independently from the outer shadow-* classes. You can layer both on the same element.
<input class="inset-shadow-sm inset-shadow-indigo-500/30 rounded-lg border border-gray-200 px-3 py-2">
Available sizes: inset-shadow-2xs, inset-shadow-xs, inset-shadow-sm, inset-shadow-none. Pair with color variants like inset-shadow-blue-500 and an opacity modifier for subtle depth on form inputs, cards, or pressed button states. No custom CSS needed.
2. inset-ring-*
A sibling to the inset shadow set. inset-ring-2 draws a solid inner border using box-shadow: inset, so it never collapses layout the way border can. Useful for a "selected" state on a card without reflowing anything.
<div class="inset-ring-2 inset-ring-indigo-500 rounded-xl p-4">
Selected plan
</div>
Typography Utilities
3. font-stretch-*
Variable fonts often include a width axis alongside weight. font-stretch utilities let you tap into it directly. The predefined scale runs from font-stretch-ultra-condensed (50%) through font-stretch-normal (100%) to font-stretch-ultra-expanded (200%). There is also percentage syntax: font-stretch-75%.
<h1 class="font-stretch-condensed text-4xl font-bold tracking-tight">
Tighter heading, same typeface
</h1>
This only has a visible effect when the loaded font face actually includes width variations. Google Fonts labels these "Variable" fonts — look for the width axis in the font specimen.
4. text-balance and text-pretty
These have been in Tailwind for a while but are genuinely underused. text-balance distributes line lengths evenly across multi-line headings. text-pretty uses the browser's widow-avoidance algorithm to prevent single orphaned words on the last line of a paragraph.
<h2 class="text-balance text-3xl font-semibold">
A well-balanced heading that wraps evenly
</h2>
<p class="text-pretty leading-relaxed">
A paragraph without orphaned last words.
</p>
Use text-balance on headings, text-pretty on body copy. The browser does the heavy lifting.
5. underline-offset-* with arbitrary values
You can dial in precise underline spacing using arbitrary values: underline-offset-[6px]. Pair with decoration-2 and decoration-indigo-500 for a custom link style that outperforms the default underline at any size.
<a href="/pricing" class="underline underline-offset-[5px] decoration-2 decoration-indigo-500 hover:decoration-indigo-700">
See pricing
</a>
Form Utilities
6. field-sizing-content
This is a genuine quality-of-life win. Apply field-sizing-content to a <textarea> and it will grow and shrink with the content automatically — no JavaScript resize listener required.
<textarea
class="field-sizing-content w-full rounded-lg border border-gray-300 px-3 py-2 min-h-[4rem]"
rows="2"
></textarea>
The opposite is field-sizing-fixed, which is the default browser behavior. Most contact forms would be improved by switching the textarea to field-sizing-content.
7. autofill:*
Browsers override input background colors when they autofill a field. The autofill: variant targets the :-webkit-autofill pseudo-class and lets you bring it back in line with your design.
<input
type="email"
class="autofill:bg-transparent autofill:text-gray-900 rounded border px-3 py-2"
>
The yellow autofill flash is one of the most visible signs of an unpolished form. This fixes it with one variant.
8. placeholder-shown:*
Reacts to whether a field is empty. Useful for showing a floating label only when the placeholder is visible (i.e., the field is empty), or for fading a helper icon while the user has typed something.
<div class="relative">
<input type="text" placeholder="Search..." class="peer w-full px-3 py-2 rounded border">
<span class="absolute right-3 top-2.5 text-gray-400 peer-placeholder-shown:opacity-100 opacity-0 transition-opacity">
🔍
</span>
</div>
Color and Scheme Utilities
9. scheme-dark / scheme-light
When you build a dark mode UI, native browser controls — scrollbars, date pickers, range inputs — stay stubbornly light unless you tell the browser otherwise. The scheme-* utilities do exactly that.
<html class="scheme-light dark:scheme-dark">
<!-- scrollbars, inputs, selects all follow the correct scheme -->
</html>
Available values: scheme-normal, scheme-light, scheme-dark, scheme-light-dark, scheme-only-light, scheme-only-dark. Apply to the root element and every native browser chrome element picks it up automatically.
10. Conic and radial gradients
Tailwind v4 ships first-class utilities for conic and radial gradients. These follow the same from/via/to pattern as linear gradients.
<div class="bg-conic-[from_0deg] from-indigo-500 via-purple-500 to-pink-500 rounded-full size-32"></div>
<div class="bg-radial from-white via-sky-100 to-sky-500 rounded-xl p-8">
Hero section with radial glow
</div>
The linear gradient utilities were also renamed in v4: bg-gradient-to-r becomes bg-linear-to-r, and you can pass an angle directly: bg-linear-45.
3D Transform Utilities
11. perspective-* and rotate-x-* / rotate-y-*
Tailwind v4 adds a proper perspective system. The perspective-* scale runs from perspective-dramatic (100px) to perspective-distant (1200px). Combine with rotate-x-* or rotate-y-* on a child for pure CSS 3D card flips, tilt effects, or skewed hero images.
<div class="perspective-midrange">
<div class="rotate-x-12 bg-white rounded-xl shadow-lg p-6 transition-transform hover:rotate-x-0 duration-300">
Tilted card
</div>
</div>
12. backface-hidden
When you flip a card using rotate-y-180, the back face of the element shows through unless you apply backface-hidden to both sides. This is a frequently forgotten step in CSS card flip tutorials.
<div class="rotate-y-180 backface-hidden">Back face</div>
Variant Utilities
13. not-* variant
The not-* variant maps directly to the CSS :not() pseudo-class and works with pseudo-classes, media queries, and @supports queries. It removes the need for workaround selectors.
<!-- Hover style only when not focused -->
<button class="bg-indigo-600 hover:not-focus:bg-indigo-700 focus:bg-indigo-800">
Save changes
</button>
<!-- Fallback layout when grid is unsupported -->
<div class="not-supports-[display:grid]:flex grid">...</div>
14. in-* variant
The in-* variant is like group-*, but it responds to any ancestor without you needing to add a group class to that parent. Useful when the parent is a third-party component you cannot modify.
<div tabindex="0">
<p class="text-gray-500 in-focus:text-gray-900 transition-colors">
Responds to parent focus without a group class
</p>
</div>
15. nth-* variants
In v4, nth-* variants accept any number and support complex expressions. Style the third list item, every other row, or a complex An+B pattern — without touching the JavaScript.
<ul>
<li class="nth-3:font-semibold nth-odd:bg-gray-50 p-3">Item</li>
<li class="nth-3:font-semibold nth-odd:bg-gray-50 p-3">Item</li>
<li class="nth-3:font-semibold nth-odd:bg-gray-50 p-3">Item (bold)</li>
</ul>
16. inert variant
The HTML inert attribute marks a subtree as non-interactive — no clicks, no focus, no text selection. Tailwind's inert: variant lets you style those sections visually to match their non-interactive state.
<fieldset inert class="inert:opacity-50 inert:cursor-not-allowed">
<!-- Entire fieldset is non-interactive and visually dimmed -->
<input type="text" placeholder="Disabled field">
</fieldset>
17. starting variant
The starting: variant maps to CSS @starting-style, which lets you define the initial state of an element before its first render or before it transitions from display: none. This unlocks pure CSS appear animations — no JavaScript toggle required.
<div
popover
id="my-popover"
class="opacity-100 starting:opacity-0 translate-y-0 starting:translate-y-2 transition-all duration-300"
>
This popover fades and slides in on open
</div>
18. open variant
Style <details>, <dialog>, and popover elements based on their open state. No JavaScript event listener, no toggled class — the browser's own open state drives it.
<details class="rounded-xl border border-gray-200 open:border-indigo-300 open:bg-indigo-50 p-4 transition-colors">
<summary class="cursor-pointer font-medium">How does it work?</summary>
<p class="mt-2 text-gray-600">The open: variant targets the native open attribute.</p>
</details>
Grid Utilities
19. grid-cols-subgrid
Subgrid lets a nested element participate in the column tracks of its parent grid — the missing piece for aligning labels and inputs inside cards that are themselves grid items. Previously this required duplicating the parent's grid-cols on every child.
<div class="grid grid-cols-3 gap-4">
<div class="col-span-3 grid grid-cols-subgrid">
<span>Label</span>
<input type="text" class="col-span-2">
</div>
</div>
20. snap-always
When building a scroll-snapped carousel, the default behavior allows the browser to skip snap points on a fast swipe. snap-always forces every snap point to settle completely before the scroll stops — each slide is guaranteed to land correctly.
<div class="flex overflow-x-auto snap-x snap-mandatory">
<div class="snap-start snap-always shrink-0 w-full">Slide 1</div>
<div class="snap-start snap-always shrink-0 w-full">Slide 2</div>
<div class="snap-start snap-always shrink-0 w-full">Slide 3</div>
</div>
Pair with scroll-smooth on the container and overscroll-contain if the carousel is nested inside a scrollable page.
Putting it together
The pattern across all twenty of these is the same: each one replaces a small block of custom CSS that you would otherwise write once, forget the property name for, and rewrite again on the next project. The field-sizing-content textarea alone is worth the upgrade to v4 if you build any kind of contact or inquiry form. The variant additions — not-*, in-*, nth-*, inert, starting, open — cover state combinations that previously required JavaScript class toggling.
The Tailwind v4 docs are the authoritative reference. When a utility is not showing up, the most common culprit is a missing @import "tailwindcss" in your CSS entry point, or a content path in your @theme block that does not cover the file where you are using it. Check those first before reaching for arbitrary values.