Skip to content

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:

border-linear-to-r border-from-pink-500 border-to-cyan-500

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 ​

bg-white
bg-gray-900
bg-sky-100

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:

bg-linear + border-linear
bg-linear + border-conic
bg-radial + border-linear
bg-conic + border-radial

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

No bg-* class (canvas)
bg-slate-800 (explicit)

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:

bg-white (opaque)
bg-white/50 (gradient bleeds through)
bg-transparent (fully visible)

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:

html
<!-- ✗ 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:

html
<!-- ✓ 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:

html
<!-- ✓ 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:

border-linear-to-t
border-linear-to-tr
border-linear-to-r
border-linear-to-br
border-linear-to-b
border-linear-to-bl
border-linear-to-l
border-linear-to-tl

Custom angle ​

Use border-linear-<angle> for a specific angle in degrees. Prefix with - for negative angles:

border-linear-45
border-linear-65
border-linear-135
-border-linear-45

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:

border-from-pink-500 border-to-blue-500
border-from-pink-500 border-via-yellow-400 border-to-blue-500
border-from-blue-500 border-to-transparent
border-from-inherit (resolves to registered initial value)

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:

html
<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:

border-from-pink-500/50 border-to-cyan-500
border-via-white/[50%]
border-radial border-from-pink-500/50 border-to-transparent

Setting gradient stop positions ​

Use border-from-<number>%, border-via-<number>%, and border-to-<number>% to set where each color stops:

border-from-10% border-via-30% border-to-90%

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:

border-radial border-via-30% border-to-100%
border-radial-[at_25%_25%]
border-radial-[at_top]

Conic gradients ​

Use border-conic-<angle> for a gradient that sweeps around a center point. Prefix with - for negative start angles:

border-conic-0
border-conic-90
border-conic-180
-border-conic-45
border-conic/longer

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 ​

/srgb
/hsl
/oklab
/oklch
/longer
/shorter
/increasing
/decreasing

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.

ModeBest for
/oklab (default)Smooth, perceptually uniform blends. No hue shifts. Best general-purpose choice.
/srgbClassic RGB blending. Can produce muddy midpoints between complementary colors.
/hslHue-based blending. Predictable hue transitions but can produce unexpected bright or gray bands.
/oklchPerceptually uniform with hue control. Good for rainbow-like gradients.
/longerTakes the long way around the hue wheel in oklch. Creates rainbow effects between two colors.
/shorterShortest path around the hue wheel (default hue interpolation in oklch).
/increasingAlways moves clockwise around the hue wheel.
/decreasingAlways 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():

border-linear-[135deg] border-from-[#ff6b35]
border-from-[oklch(0.6_0.25_330)] border-to-[oklch(0.7_0.2_200)]
border-from-[hsl(330,80%,50%)] border-to-[hsl(200,80%,50%)]

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:

border-from-(color:--brand-from) border-to-(color:--brand-to)

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:

UtilityHintExample
border-from-*requiredborder-from-(color:--brand-from)
border-from-*requiredborder-from-(percentage:--stop-start)
border-via-*requiredborder-via-(color:--brand-accent)
border-to-*requiredborder-to-(color:--brand-to)
border-to-*requiredborder-to-(percentage:--stop-end)
border-linear-*noneborder-linear-(--angle)
border-linear-to-*noneborder-linear-to-(--direction)
border-conic-*noneborder-conic-(--start-angle)
border-radial-*noneborder-radial-(--position)
border-spin-duration-*noneborder-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:

Hover to shift gradient

Border width ​

The gradient fills whatever border width you set. Thicker borders show more of the gradient:

border (1px)
border-2
border-4
border-8

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:

solid
dashed
dotted
double

How it works ​

The technique is CSS background clipping. The utility sets a transparent border, then stacks two background layers behind it:

  1. Padding-box layer. Your background color, clipped to the content and padding area
  2. 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:

css
@import 'tw-jib-css/border-gradient';

Baseline status

What these utilities are built on, live from the Web Platform Dashboard.