You upgrade a Laravel project to Tailwind v4, run the upgrade tool, and your marketing hero is suddenly a flat box. The gradient classes you reached for daily got renamed in v4, and two whole new gradient types showed up alongside them. This is the at-a-glance reference: what changed, what is new, and the colour-space modifiers that quietly make every gradient look better.
If you have not migrated yet, the Tailwind v3 to v4 Laravel upgrade walkthrough handles the codemod. Everything below assumes you are already on v4.3 or later.
The class rename — bg-gradient-to became bg-linear-to#
The big v3 → v4 breaking change in this corner of the framework is the rename. bg-gradient-to-r is now bg-linear-to-r. The reason is alignment with the native CSS function — linear-gradient(), radial-gradient(), conic-gradient() — so the Tailwind class names finally match what they compile to. The colour stops did not change: from-*, via-*, to-* work identically.
{{-- Tailwind v3 --}}
<div class="bg-gradient-to-r from-indigo-500 via-purple-500 to-pink-500">…</div>
{{-- Tailwind v4 --}}
<div class="bg-linear-to-r from-indigo-500 via-purple-500 to-pink-500">…</div>
The eight directional keywords (-r, -l, -t, -b, -tr, -tl, -br, -bl) are all there. What is new: you can pass an angle directly. bg-linear-45 produces a 45° gradient, bg-linear-180 is to bottom, and arbitrary values like bg-linear-[120deg] still work when you need a value the scale does not cover.
<div class="bg-linear-45 from-rose-500 to-amber-500">
Diagonal gradient at exactly 45 degrees
</div>
<div class="bg-linear-[120deg] from-cyan-400 to-blue-700">
Arbitrary angle when 90/45/etc. is not enough
</div>
The official upgrade tool catches bg-gradient-to-* and rewrites it. The version it does not catch is anything built dynamically — class strings concatenated in Blade or PHP. Grep your codebase for bg-gradient- after the upgrade and you will usually find a few stragglers in dynamic class builders. This is the same trap that bites the class-based dark mode setup in Tailwind v4: the codemod only sees what is statically parseable.
Radial gradients with bg-radial#
bg-radial is the v4 utility for the CSS radial-gradient() function — gradients that expand outward from a centre point. There was no first-class utility for this in v3; you had to drop into an arbitrary value or install a plugin. In v4 it pairs with the same from-* / via-* / to-* stops as the linear version.
<div class="size-64 bg-radial from-fuchsia-400 to-fuchsia-900">
Glow card — radial from centre
</div>
The default origin is the geometric centre of the element. To move it, use bg-radial-[at_<position>]. The position can be a keyword (top, bottom_left) or a percentage pair.
{{-- Origin at the top-left corner --}}
<div class="size-64 bg-radial-[at_top_left] from-amber-300 to-orange-900">…</div>
{{-- Origin at 25% from the left, 25% from the top --}}
<div class="size-64 bg-radial-[at_25%_25%] from-sky-300 to-indigo-900">…</div>
The hero "spotlight" pattern most product pages use is just bg-radial-[at_top] with a near-transparent to-* colour — the highlight blends into the page below it. Combine with bg-zinc-950 as the base on a <body> and the spotlight floats above the dark backdrop without any image asset.
Conic gradients with bg-conic#
bg-conic is the new utility for CSS conic gradients — colours that sweep around a central point rather than radiating outward. They are how you build pie-chart segments, loader rings, or the colourful avatar borders Discord uses without an SVG.
<div class="size-32 rounded-full bg-conic from-blue-600 via-cyan-300 to-sky-400">
Conic loader ring
</div>
By default the sweep starts at 0° (the top of the element) and rotates clockwise. To start somewhere else, use the angle scale: bg-conic-90 starts the sweep at 90°, bg-conic-180 at 180°. You can also pass arbitrary degree values with the bracket syntax.
{{-- Sweep starts pointing right --}}
<div class="size-32 rounded-full bg-conic-90 from-rose-500 to-rose-100">…</div>
{{-- The "rainbow ring" — full sweep, hue-rotating colours --}}
<div class="size-32 rounded-full bg-conic from-red-500 via-yellow-400 via-green-400 via-blue-500 to-red-500">…</div>
Note that conic gradients on a rounded-full element give you a wheel; on a rectangle you get a clock-hand sweep. Both have their uses — the wheel is great for avatars and progress rings, the sweep is what you want for hero "shimmer" effects on banners.
Colour interpolation in oklab and friends#
Here is the part most v3 muscle memory misses. In v4 the default colour interpolation space is oklab — a perceptually uniform space designed for blends. The practical effect is that gradients between distant hues no longer pass through muddy grey at the midpoint. from-blue-500 to-yellow-500 used to look dirty in sRGB; in v4's default oklab it looks clean.
You can override the interpolation space per gradient with a /{space} modifier on the utility class:
{{-- Default (oklab) — perceptual blend --}}
<div class="bg-linear-to-r from-pink-500 to-cyan-500">Smooth, even brightness</div>
{{-- oklch — polar space, vivid hue rotation --}}
<div class="bg-linear-to-r/oklch from-pink-500 to-cyan-500">More saturated mid-range</div>
{{-- srgb — the legacy v3 behaviour --}}
<div class="bg-linear-to-r/srgb from-pink-500 to-cyan-500">Muddier mid-range</div>
{{-- hsl — polar, sometimes useful for retro effects --}}
<div class="bg-linear-to-r/hsl from-red-500 to-green-500">Passes through yellow</div>
On polar spaces (oklch, hsl) there are two ways round the colour wheel between any two hues. The /longer and /shorter modifiers pick which path. /shorter (the default) takes the most direct route. /longer takes the long way round, which is how you get those psychedelic "spin through every hue" loader rings.
{{-- Shortest path, indigo straight to violet --}}
<div class="bg-conic/oklch from-indigo-500 to-violet-500">…</div>
{{-- Long way round — sweeps through red, yellow, green, blue --}}
<div class="bg-conic/oklch/longer from-indigo-500 to-violet-500">Full rainbow ring</div>
The default oklab already covers 90% of cases, but if you find a gradient looking flat where you expected vivid, switch to /oklch and try again. If it looks washed out, /longer on a polar space is usually the answer.
Three recipes that earn the new utilities#
The new utility set unlocks effects that took an SVG or a Figma export in v3. Three I reach for constantly:
{{-- 1. Button shimmer — animate with a transition --}}
<button class="bg-linear-to-r from-indigo-500 via-purple-500 to-pink-500 px-4 py-2 text-white">
Get started
</button>
{{-- 2. Hero glow — radial blob behind content --}}
<section class="relative isolate overflow-hidden">
<div class="absolute inset-0 -z-10 bg-radial-[at_top] from-indigo-500/30 to-transparent"></div>
<h1>Headline floats above the glow</h1>
</section>
{{-- 3. Conic loader ring --}}
<div class="size-12 animate-spin rounded-full bg-conic/oklch from-blue-600 to-blue-100"></div>
The hero glow is the one I get the most questions about. The trick is to-transparent (not to-zinc-950 or whatever your background is) so the gradient fades into whatever sits behind it — which means you can drop the same component on any page section and the glow blends with the page colour. The from-indigo-500/30 opacity stop is what controls how strong the glow looks. Pair it with a Tailwind v4 container query wrapper on the hero and the glow scales with the slot, not the viewport.
The loader uses oklch because the sweep crosses a wide hue range and you want the mid-tones to stay saturated. With default oklab the middle of the ring looks slightly grey.
Gotchas and Edge Cases#
A few sharp edges I have hit since the rename.
Dynamic classes the upgrade tool misses. npx @tailwindcss/upgrade rewrites class names it can statically see. Anything built at runtime — 'bg-gradient-to-' . $direction in a Livewire computed property, or class strings inside an Alpine :class expression — is invisible to the codemod. Grep your project for bg-gradient- after the upgrade. Anything left is a runtime bug waiting to happen, because the v4 build will not emit those classes.
Arbitrary values cannot take the /oklch modifier. This one bit me. The modifier syntax is parsed off the utility, not the arbitrary value. bg-linear-[120deg]/oklch does not work. To apply a custom interpolation space inside an arbitrary value, write the whole gradient by hand: bg-linear-[120deg_in_oklch] (the keyword goes inside the brackets). For most cases the keyword utilities plus the /oklch modifier are fine — the arbitrary value escape hatch is rarely necessary.
Three-stop gradients want one via-*. You can stack multiple via-* colour stops, and the result is a gradient that passes through each of them in order. This is how the rainbow conic ring works. The trap is forgetting to mention every stop — the gradient still renders but with abrupt transitions where you expected smooth ones. If a multi-stop gradient looks chunky, add an explicit via-* between every pair of adjacent colours.
to-transparent is the modern way to fade out. Old Tailwind v3 examples used to write to-white/0 or hack in an arbitrary rgba(). In v4 to-transparent works on every gradient utility and produces a clean fade, which is exactly what you want for spotlight effects against an unknown page background.
Conic gradients on rectangles are not wheels. I keep seeing bg-conic slapped on a non-rounded element and the result is a clock-hand sweep, not a colour wheel. If you want the wheel, add rounded-full. If you want the sweep, that is also a legitimate look — Apple does it on their event banners — but it is a different effect.
Wrapping Up#
The rename is the disruptive part, but the radial and conic utilities are why this v4 corner is worth learning. Once bg-radial-[at_top] is in your reach, the days of hero sections that needed an exported SVG glow are over. Once bg-conic/oklch is in your reach, loader rings and avatar borders stop needing a third-party component.
Run a project-wide search for bg-gradient- next time you ship — anything the upgrade tool missed will be dynamic strings. If you are still mid-migration, the Tailwind v3 to v4 upgrade walkthrough covers the broader codemod. For admin work, the Filament v4 custom form field walkthrough shows where these gradients tend to land in real product UIs — call-to-action buttons inside resource pages and stat cards on dashboards.
FAQ#
What is the difference between bg-gradient-to-r and bg-linear-to-r in Tailwind?
bg-gradient-to-r is the Tailwind v3 utility for a left-to-right linear gradient. bg-linear-to-r is the v4 rename of the same utility — it produces identical CSS but aligns the class name with the underlying linear-gradient() function, and it sits alongside the new bg-radial and bg-conic siblings. In a v4 project the bg-gradient-* form no longer ships; you have to use bg-linear-* for linear gradients.
How do I create a radial gradient in Tailwind CSS v4?
Use the bg-radial utility with the same from-* / via-* / to-* stops as a linear gradient — bg-radial from-pink-400 to-fuchsia-700 produces a centred radial blend. To move the origin off-centre, use the bracket syntax bg-radial-[at_<position>], where the position is a keyword like top_left or a percentage pair like 25%_25%. The combination handles every common "spotlight" effect without arbitrary CSS.
How do I create a conic gradient with Tailwind?
Use bg-conic with the standard colour stops. By default the sweep starts at the top of the element and rotates clockwise. To shift the starting angle, use bg-conic-90, bg-conic-180, or any value on the angle scale; for non-standard angles, pass an arbitrary value. Wrap the element in rounded-full if you want a colour wheel; on a rectangle you get a clock-hand sweep instead.
What is oklab interpolation and why is it the default in Tailwind v4?
oklab is a perceptually uniform colour space designed so that equal numeric steps produce equal visual steps. Tailwind v4 defaults to interpolating gradients in oklab because it avoids the muddy grey midpoint you get when blending distant hues in legacy sRGB. A from-blue-500 to-yellow-500 gradient that looked dirty in v3 looks clean in v4 with no extra modifiers — that is oklab doing its job behind the scenes.
Can I still use arbitrary values for gradient directions in Tailwind v4?
Yes. bg-linear-[120deg], bg-radial-[at_25%_75%], and bg-conic-[from_45deg] all work in v4 exactly as they did in v3, and they are still the escape hatch for designs that need a value the keyword scale does not cover. The only catch is the /oklch (and other interpolation) modifier — it cannot be applied to an arbitrary value via the / syntax. To set the interpolation space inside an arbitrary value, bake it into the value itself with the in_oklch keyword (e.g. bg-linear-[120deg_in_oklch]).
How do I add three or more colour stops in a Tailwind gradient?
Stack via-* utilities between your from-* and to-*. bg-linear-to-r from-red-500 via-yellow-400 via-green-400 via-blue-500 to-red-500 produces a five-stop gradient that sweeps through the rainbow. The stops are placed in order at evenly spaced positions; if you need to control the exact percentage of each stop, use arbitrary positions on the colour stop utilities (via-yellow-400 via-30%) — this works on the same via-* chains.