Border gradient
Linear, radial and conic gradient borders. Same grammar as Tailwind's bg-linear-*, applied to borders. 8 interpolation modes. For animated spinning borders, see Border Spin.
Browser support
Built on registered custom properties and gradient color interpolation, which is also what the interpolation modes (/shorter, /longer, etc.) ride on. No relative color syntax is involved. Live status for both is at the foot of this page.
Gradient stops from CSS variables must carry a type hint
border-from-*, border-via-* and border-to-* take either a color or a position, so a CSS variable has to say which: border-from-(color:--brand) or border-from-(percentage:--stop). The untyped border-from-(--brand) matches neither and emits no rule at all, so the stop silently keeps its default. The full table is below.
Quick reference
| class | styles |
|---|---|
| border-linear-to-t | --jib-border-gradient: linear-gradient(to top var(--jib-gradient-interpolation), var(--jib-border-gradient-stops)) |
| border-linear-to-tr | --jib-border-gradient: linear-gradient(to top right var(--jib-gradient-interpolation), var(--jib-border-gradient-stops)) |
| border-linear-to-r | --jib-border-gradient: linear-gradient(to right var(--jib-gradient-interpolation), var(--jib-border-gradient-stops)) |
| border-linear-to-br | --jib-border-gradient: linear-gradient(to bottom right var(--jib-gradient-interpolation), var(--jib-border-gradient-stops)) |
| border-linear-to-b | --jib-border-gradient: linear-gradient(to bottom var(--jib-gradient-interpolation), var(--jib-border-gradient-stops)) |
| border-linear-to-bl | --jib-border-gradient: linear-gradient(to bottom left var(--jib-gradient-interpolation), var(--jib-border-gradient-stops)) |
| border-linear-to-l | --jib-border-gradient: linear-gradient(to left var(--jib-gradient-interpolation), var(--jib-border-gradient-stops)) |
| border-linear-to-tl | --jib-border-gradient: linear-gradient(to top left var(--jib-gradient-interpolation), var(--jib-border-gradient-stops)) |
| border-linear-to-[<value>] | --jib-border-gradient-position: <value> |
| border-linear-<angle> | --jib-border-gradient: linear-gradient(<angle>deg var(--jib-gradient-interpolation), var(--jib-border-gradient-stops)) |
| border-radial | --jib-border-gradient: radial-gradient(var(--jib-gradient-interpolation), var(--jib-border-gradient-stops)) |
| border-radial-[<value>] | --jib-border-gradient: radial-gradient(<value>, var(--jib-border-gradient-stops)) |
Basic usage
Linear gradient border
Use border-linear-to-<direction> with border-from-<color> and border-to-<color> to create a gradient border:
With a background color
Border gradients work alongside Tailwind's bg-* utilities. Apply a bg-* class and the module layers your background inside the border gradient.
Solid background colors
Gradient backgrounds
Tailwind gradient backgrounds and border gradients coexist. The background gradient layers inside the padding area while the border gradient fills the border area. The background and border gradient types don't need to match:
Inherited backgrounds
The background color does not inherit from parent elements. The module registers --jib-background-image with inherits: false, so a child without its own bg-* class gets the initial value, linear-gradient(canvas 0 0), rather than the parent's color:
Parent: bg-slate-800
Transparent and semi-transparent backgrounds
The border-gradient technique works by stacking two background layers: a padding-box layer, your background, on top of a border-box layer, the gradient. A transparent or semi-transparent background lets the gradient layer show through into the content area, not just the border:
This falls out of the clipping technique. The padding-box layer must be fully opaque to mask the gradient behind it. If you want a see-through content area with only a gradient ring, reach for mask-composite instead: paint the gradient over the whole element and mask out everything but the border. It keeps border-radius, unlike border-image, and costs you a narrower support floor (Chrome 120+, Firefox 53+, Safari 15.4+).
What doesn't work
WARNING
Backgrounds set outside Tailwind's bg-* classes won't show through the border gradient. The border-gradient utilities set a background shorthand that replaces any background or background-color from custom CSS classes or inline styles.
The border-gradient utility's background shorthand overwrites a background set by a custom CSS class or an inline style. --jib-background-image stays at its initial value, linear-gradient(canvas 0 0), so the element loses the background you meant it to have:
<!-- ✗ Custom class: the background gets overwritten -->
<style>
.my-card {
background: #e0f2fe;
}
</style>
<div class="my-card border-4 border-linear-to-r border-from-pink-500 border-to-cyan-500">
Background will be canvas, not #e0f2fe
</div>
<!-- ✗ Inline style: same issue -->
<div
style="background-color: #e0f2fe"
class="border-4 border-linear-to-r border-from-pink-500 border-to-cyan-500"
>
Background will be canvas, not #e0f2fe
</div>Workarounds
Route the color through Tailwind's bg-* pipeline so it feeds into --jib-background-image:
<!-- ✓ Arbitrary value -->
<div class="bg-[#e0f2fe] border-4 border-linear-to-r border-from-pink-500 border-to-cyan-500">
...
</div>
<!-- ✓ Custom property via bare-value syntax -->
<div class="bg-(--my-color) border-4 border-linear-to-r border-from-pink-500 border-to-cyan-500">
...
</div>Or set --jib-background-image directly to bypass the bg-* utility:
<!-- ✓ Setting the custom property directly -->
<div
style="--jib-background-image: linear-gradient(#e0f2fe 0 0)"
class="border-4 border-linear-to-r border-from-pink-500 border-to-cyan-500"
>
...
</div>Gradient direction
Directional
Use border-linear-to-{t|tr|r|br|b|bl|l|tl} for predefined directions:
Custom angle
Use border-linear-<angle> for a specific angle in degrees. Prefix with - for negative angles:
Color stops
Setting gradient colors
Use border-from-<color>, border-via-<color>, and border-to-<color> to set gradient color stops. These accept any Tailwind color, including transparent and inherit:
Stop opacity
Every stop takes an opacity modifier in the three spellings Tailwind's own color utilities accept — a bare number is a percentage, a bracketed percentage passes through, and a bracketed number is a 0–1 alpha:
<div class="border-linear-to-r border-from-pink-500/50 border-to-cyan-500"></div>
<div class="border-linear-to-r border-from-pink-500/[50%] border-to-cyan-500"></div>
<div class="border-linear-to-r border-from-pink-500/[.5] border-to-cyan-500"></div>Pair a faded stop with border-to-transparent for a glow that falls off rather than ending on a hard edge:
Setting gradient stop positions
Use border-from-<number>%, border-via-<number>%, and border-to-<number>% to set where each color stops:
Radial gradients
Use border-radial for a gradient that radiates from the center. Use bracket notation to set a custom position, either percentage-based or keyword-based:
Conic gradients
Use border-conic-<angle> for a gradient that sweeps around a center point. Prefix with - for negative start angles:
Interpolation modes
Control how colors blend using the slash modifier on the gradient type. The default is oklab. See the Color Spaces guide for an overview of how these spaces differ.
Linear
The same 8 modifiers apply to border-radial and border-conic gradients: border-radial/oklch, border-conic/longer, etc.
Choosing an interpolation mode
See Color Spaces for a deeper look at how each space affects blending.
| Mode | Best for |
|---|---|
/oklab (default) | Smooth, perceptually uniform blends. No hue shifts. Best general-purpose choice. |
/srgb | Classic RGB blending. Can produce muddy midpoints between complementary colors. |
/hsl | Hue-based blending. Predictable hue transitions but can produce unexpected bright or gray bands. |
/oklch | Perceptually uniform with hue control. Good for rainbow-like gradients. |
/longer | Takes the long way around the hue wheel in oklch. Creates rainbow effects between two colors. |
/shorter | Shortest path around the hue wheel (default hue interpolation in oklch). |
/increasing | Always moves clockwise around the hue wheel. |
/decreasing | Always moves counter-clockwise around the hue wheel. |
Using a custom value
Use bracket notation for custom colors and angles. Color stops accept any CSS color format: hex, rgb(), hsl(), oklch():
Using a custom variable
Reference CSS custom properties with (--var). Where a utility accepts more than one kind of value, add a type hint — (type:--var) — so Tailwind knows which one you mean:
The stop utilities take either a color or a position, so those need the hint. The rest take one kind of value and accept the plain form:
| Utility | Hint | Example |
|---|---|---|
border-from-* | required | border-from-(color:--brand-from) |
border-from-* | required | border-from-(percentage:--stop-start) |
border-via-* | required | border-via-(color:--brand-accent) |
border-to-* | required | border-to-(color:--brand-to) |
border-to-* | required | border-to-(percentage:--stop-end) |
border-linear-* | none | border-linear-(--angle) |
border-linear-to-* | none | border-linear-to-(--direction) |
border-conic-* | none | border-conic-(--start-angle) |
border-radial-* | none | border-radial-(--position) |
border-spin-duration-* | none | border-spin-duration-(--speed) |
An untyped variable on border-from-*, border-via-* or border-to-* matches nothing and emits no rule, so the stop keeps its default rather than failing loudly.
Applying conditionally
Hover and focus states
Prefix a border gradient utility with a state variant like hover:* to only apply it in that state:
Border width
The gradient fills whatever border width you set. Thicker borders show more of the gradient:
Border style and border color
The gradient is a background layer clipped to border-box, with border-color held at transparent so it shows through. A border-* colour on the same element does not override that, so every border style looks the same:
How it works
The technique is CSS background clipping. The utility sets a transparent border, then stacks two background layers behind it:
- Padding-box layer. Your background color, clipped to the content and padding area
- Border-box layer. The gradient, filling the whole box including the border area
The border area shows the gradient because the padding-box background doesn't cover it. This is a pure CSS technique that works with border-radius and doesn't require pseudo-elements.
For animated spinning borders, see Border Spin.
Import
Included in @import 'tw-jib-css'. To import individually:
@import 'tw-jib-css/border-gradient';Baseline status
What these utilities are built on, live from the Web Platform Dashboard.