Animated Border Gradient

Animated Border Gradient With TailwindCSS

Animated Border Gradient

This builds on the static gradient-border trick and makes the gradient move, so a button gets a slowly shifting, animated colored frame. The idea is to make the gradient much larger than the element and then animate its background-position back and forth, which slides the colors across the border in a continuous loop. It's a small, attention-grabbing accent I use on a primary call-to-action when I want a bit of motion without a heavy animation library.

  1. Create the boilerplate for the Button
<div className="flex h-40 w-full flex-row items-center justify-center">
  <button className="inline-block rounded-md bg-white bg-gradient-to-r from-red-500 via-purple-500 to-blue-500 bg-[length:400%_400%] p-1">
    <span className="block rounded-md bg-slate-900 px-5 py-3 font-bold text-white"> algochurn.com </span>
  </button>
</div>

  1. Add the required border animation in tailwind.config.js file
/** @type {import('tailwindcss').Config} */
module.exports = {
  theme: {
    extend: {
      animation: {
        border: 'border 4s ease infinite',
      },
      keyframes: {
        border: {
          '0%, 100%': { backgroundPosition: '0% 50%' },
          '50%': { backgroundPosition: '100% 50%' },
        },
      },
    },
  },
  plugins: [],
}

  1. Add animate-border className to the Button.
<div className="flex h-40 w-full flex-row items-center justify-center">
  <button className="animate-border inline-block rounded-md bg-white bg-gradient-to-r from-red-500 via-purple-500 to-blue-500 bg-[length:400%_400%] p-1">
    <span className="block rounded-md bg-slate-900 px-5 py-3 font-bold text-white"> algochurn.com </span>
  </button>
</div>

How it works

The static structure is the same nested-box border trick: the outer button carries bg-gradient-to-r from-red-500 via-purple-500 to-blue-500 with p-1 padding, and the inner span has bg-slate-900, so only the padded gradient edge shows as a border.

The motion comes from two pieces. First, bg-[length:400%_400%] blows the gradient up to four times the element's size in both directions, which leaves plenty of off-screen gradient to slide into view. Second, the custom border keyframe defined in tailwind.config.js animates backgroundPosition from 0% 50% to 100% 50% and back ('0%, 100%' and '50%' are the keyframe stops), and the animation: 'border 4s ease infinite' entry runs that loop forever over four seconds. Adding the generated animate-border class in step 3 is what actually attaches the animation to the button, that's the only difference between the static button in step 1 and the animated one in step 3.

Notes & variations

Because the animation is registered in tailwind.config.js, this needs a Tailwind setup with access to the config (it won't work with the Play CDN's default build). Tune the feel by changing the 4s duration (longer is calmer, shorter is more frantic) and the 400% size (a larger value means the colors travel farther per cycle). Swap the from-/via-/to- colors for your own palette, and change the inner bg-slate-900 to recolor the button face.

For accessibility, this is continuous motion, so it's polite to disable it for users who opt out, you can guard the animation with a @media (prefers-reduced-motion: reduce) rule, or conditionally drop the animate-border class, so the button falls back to the static gradient border. Keep the button a real <button> (as here) so it stays keyboard- and screen-reader-friendly.

  1. Demo