08 / 30
All 30 in 30 Tailwind CSS Hover Effects
- 01Tailwind Underline Draw Hover Effect
- 02Tailwind Text Glitch Hover Effect
- 03Tailwind Letter Spacing Expand Hover Effect
- 04Tailwind Gradient Text Reveal Hover Effect
- 05Tailwind Split Text Hover Effect
- 06Tailwind Neon Glow Text Hover Effect
- 07Tailwind Magnetic Liquid Button Hover Effect
- 08Tailwind Border Draw Hover Effect
- 09Tailwind Shimmer Shine Button Hover Effect
- 10Tailwind Fill Wipe Button Hover Effect
- 11Tailwind 3D Press Button Hover Effect
- 12Tailwind Ripple Button Hover Effect
- 13Tailwind 3D Tilt Card Hover Effect
- 14Tailwind Card Flip Hover Effect
- 15Tailwind Glassmorphism Card Hover Effect
- 16Tailwind Spotlight Card Hover Effect
- 17Tailwind Slide Reveal Card Hover Effect
- 18Tailwind Stack Lift Card Hover Effect
- 19Tailwind Zoom Pan Image Hover Effect
- 20Tailwind Color Channel Split Hover Effect
- 21Tailwind Duotone Image Hover Effect
- 22Tailwind Curtain Reveal Image Hover Effect
- 23Tailwind Ken Burns Image Hover Effect
- 24Tailwind Image Tilt Depth Hover Effect
- 25Tailwind Underline Slide Nav Hover Effect
- 26Tailwind Highlight Fill Nav Hover Effect
- 27Tailwind Strikethrough Hover Link Effect
- 28Tailwind Inline Word Swap Hover Effect
- 29Tailwind Dot Trail Cursor Hover Effect
- 30Tailwind Magnetic Cursor Pull Hover Effect
Tailwind Border Draw Hover Effect
Six border-draw hovers — clockwise stroke, corner brackets, double rail, dashed grow, a spinning conic ring and an inset box-shadow flood. The conic ring animates a registered --angle rather than rotating the element, which is what keeps a wide rectangle from flailing.
Untitled UI Pro: 5,000+ React + Tailwind CSS v4 components · from $349 one-time
Untitled UI React · Affiliate link
The code
<section class="thv-08 w-full min-h-svh grid place-items-center bg-thv08-bg font-thv08-sans px-6 py-14">
<div class="w-[min(880px,100%)] grid grid-cols-[repeat(auto-fit,minmax(230px,1fr))] gap-9">
<div class="flex flex-col items-center gap-5 px-5 py-10 rounded-xl bg-white/[0.025] border border-white/[0.07]">
<button type="button" class="relative min-h-11 px-8 py-3 bg-transparent text-[0.95rem] font-semibold tracking-[0.05em] text-thv08-amber cursor-pointer transition-[color,box-shadow] duration-300 delay-[390ms] hover:text-thv08-text hover:shadow-[inset_2px_0_0_var(--color-thv08-amber),inset_-2px_0_0_var(--color-thv08-amber)] hover:delay-200 focus-visible:text-thv08-text focus-visible:shadow-[inset_2px_0_0_var(--color-thv08-amber),inset_-2px_0_0_var(--color-thv08-amber)] focus-visible:outline-2 focus-visible:outline-offset-3 focus-visible:outline-thv08-amber before:content-[''] before:absolute before:top-0 before:right-0 before:w-0 before:h-0.5 before:bg-thv08-amber before:transition-[width] before:duration-200 after:content-[''] after:absolute after:bottom-0 after:left-0 after:w-0 after:h-0.5 after:bg-thv08-amber after:transition-[width] after:duration-200 after:delay-400 hover:before:w-full hover:after:w-full hover:after:delay-200 focus-visible:before:w-full focus-visible:after:w-full motion-reduce:before:transition-none motion-reduce:after:transition-none">Clockwise Draw</button>
<span class="text-[11px] tracking-[0.12em] uppercase text-thv08-dim">clockwise stroke</span>
</div>
<div class="flex flex-col items-center gap-5 px-5 py-10 rounded-xl bg-white/[0.025] border border-white/[0.07]">
<button type="button" class="relative overflow-visible min-h-11 px-8 py-3 bg-transparent text-[0.95rem] font-semibold tracking-[0.05em] text-thv08-orange cursor-pointer transition-colors duration-300 focus-visible:outline-2 focus-visible:outline-offset-4 focus-visible:outline-thv08-orange before:content-[''] before:absolute before:-top-0.5 before:-left-0.5 before:w-3 before:h-3 before:border-t-2 before:border-l-2 before:border-thv08-orange before:transition-[width,height] before:duration-250 after:content-[''] after:absolute after:-bottom-0.5 after:-right-0.5 after:w-3 after:h-3 after:border-b-2 after:border-r-2 after:border-thv08-orange after:transition-[width,height] after:duration-250 hover:before:w-[calc(100%+4px)] hover:before:h-[calc(100%+4px)] hover:after:w-[calc(100%+4px)] hover:after:h-[calc(100%+4px)] focus-visible:before:w-[calc(100%+4px)] focus-visible:before:h-[calc(100%+4px)] focus-visible:after:w-[calc(100%+4px)] focus-visible:after:h-[calc(100%+4px)] motion-reduce:before:transition-none motion-reduce:after:transition-none">Corner Flash</button>
<span class="text-[11px] tracking-[0.12em] uppercase text-thv08-dim">corner brackets</span>
</div>
<div class="flex flex-col items-center gap-5 px-5 py-10 rounded-xl bg-white/[0.025] border border-white/[0.07]">
<button type="button" class="relative overflow-hidden min-h-11 px-8 py-3 bg-transparent text-[0.95rem] font-semibold tracking-[0.05em] text-thv08-red cursor-pointer transition-colors duration-300 hover:text-thv08-text focus-visible:text-thv08-text focus-visible:outline-2 focus-visible:outline-offset-3 focus-visible:outline-thv08-red before:content-[''] before:absolute before:top-0 before:-left-full before:w-full before:h-0.5 before:bg-thv08-red before:transition-[left] before:duration-350 before:ease-[cubic-bezier(.4,0,.2,1)] after:content-[''] after:absolute after:bottom-0 after:-right-full after:w-full after:h-0.5 after:bg-thv08-red after:transition-[right] after:duration-350 after:ease-[cubic-bezier(.4,0,.2,1)] hover:before:left-0 hover:after:right-0 focus-visible:before:left-0 focus-visible:after:right-0 motion-reduce:before:transition-none motion-reduce:after:transition-none">Double Rail</button>
<span class="text-[11px] tracking-[0.12em] uppercase text-thv08-dim">dual-rail slide</span>
</div>
<div class="flex flex-col items-center gap-5 px-5 py-10 rounded-xl bg-white/[0.025] border border-white/[0.07]">
<button type="button" class="min-h-11 px-8 py-3 bg-transparent border-2 border-dashed border-transparent text-[0.95rem] font-semibold tracking-[0.05em] text-thv08-yellow cursor-pointer transition-[border-color,color,padding] duration-300 hover:border-thv08-yellow hover:text-thv08-text hover:px-10 focus-visible:border-thv08-yellow focus-visible:text-thv08-text focus-visible:outline-2 focus-visible:outline-offset-3 focus-visible:outline-thv08-yellow motion-reduce:transition-[border-color,color] motion-reduce:hover:px-8">Dashed Grow</button>
<span class="text-[11px] tracking-[0.12em] uppercase text-thv08-dim">dashed border scale</span>
</div>
<div class="flex flex-col items-center gap-5 px-5 py-10 rounded-xl bg-white/[0.025] border border-white/[0.07]">
<button type="button" class="relative isolate overflow-visible min-h-11 px-8 py-3 bg-transparent text-[0.95rem] font-semibold tracking-[0.05em] text-thv08-text cursor-pointer focus-visible:outline-2 focus-visible:outline-offset-4 focus-visible:outline-thv08-amber before:content-[''] before:absolute before:-inset-0.5 before:-z-10 before:rounded-[4px] before:opacity-0 before:transition-opacity before:duration-300 before:[--thv08-angle:0deg] before:[background:conic-gradient(from_var(--thv08-angle),transparent_0%,var(--color-thv08-amber)_30%,var(--color-thv08-orange)_50%,transparent_70%)] after:content-[''] after:absolute after:inset-0 after:-z-10 after:rounded-[2px] after:bg-thv08-bg hover:before:opacity-100 hover:before:animate-thv08-spin focus-visible:before:opacity-100 focus-visible:before:animate-thv08-spin motion-reduce:hover:before:animate-none">Gradient Sweep</button>
<span class="text-[11px] tracking-[0.12em] uppercase text-thv08-dim">conic border sweep</span>
</div>
<div class="flex flex-col items-center gap-5 px-5 py-10 rounded-xl bg-white/[0.025] border border-white/[0.07]">
<button type="button" class="min-h-11 px-8 py-3 bg-transparent text-[0.95rem] font-semibold tracking-[0.05em] text-thv08-gold cursor-pointer shadow-[inset_0_0_0_0_var(--color-thv08-amber)] transition-[box-shadow,color] duration-400 ease-[cubic-bezier(.4,0,.2,1)] hover:text-black hover:shadow-[inset_0_0_0_60px_var(--color-thv08-amber)] focus-visible:text-black focus-visible:shadow-[inset_0_0_0_60px_var(--color-thv08-amber)] focus-visible:outline-2 focus-visible:outline-offset-3 focus-visible:outline-thv08-amber motion-reduce:transition-none">Inset Reveal</button>
<span class="text-[11px] tracking-[0.12em] uppercase text-thv08-dim">box-shadow inset</span>
</div>
</div>
</section><section class="thv-08 w-full min-h-svh grid place-items-center bg-thv08-bg font-thv08-sans px-6 py-14">
<div class="w-[min(880px,100%)] grid grid-cols-[repeat(auto-fit,minmax(230px,1fr))] gap-9">
<div class="flex flex-col items-center gap-5 px-5 py-10 rounded-xl bg-white/[0.025] border border-white/[0.07]">
<button type="button" class="relative min-h-11 px-8 py-3 bg-transparent text-[0.95rem] font-semibold tracking-[0.05em] text-thv08-amber cursor-pointer transition-[color,box-shadow] duration-300 delay-[390ms] hover:text-thv08-text hover:shadow-[inset_2px_0_0_var(--color-thv08-amber),inset_-2px_0_0_var(--color-thv08-amber)] hover:delay-200 focus-visible:text-thv08-text focus-visible:shadow-[inset_2px_0_0_var(--color-thv08-amber),inset_-2px_0_0_var(--color-thv08-amber)] focus-visible:outline-2 focus-visible:outline-offset-3 focus-visible:outline-thv08-amber before:content-[''] before:absolute before:top-0 before:right-0 before:w-0 before:h-0.5 before:bg-thv08-amber before:transition-[width] before:duration-200 after:content-[''] after:absolute after:bottom-0 after:left-0 after:w-0 after:h-0.5 after:bg-thv08-amber after:transition-[width] after:duration-200 after:delay-400 hover:before:w-full hover:after:w-full hover:after:delay-200 focus-visible:before:w-full focus-visible:after:w-full motion-reduce:before:transition-none motion-reduce:after:transition-none">Clockwise Draw</button>
<span class="text-[11px] tracking-[0.12em] uppercase text-thv08-dim">clockwise stroke</span>
</div>
<div class="flex flex-col items-center gap-5 px-5 py-10 rounded-xl bg-white/[0.025] border border-white/[0.07]">
<button type="button" class="relative overflow-visible min-h-11 px-8 py-3 bg-transparent text-[0.95rem] font-semibold tracking-[0.05em] text-thv08-orange cursor-pointer transition-colors duration-300 focus-visible:outline-2 focus-visible:outline-offset-4 focus-visible:outline-thv08-orange before:content-[''] before:absolute before:-top-0.5 before:-left-0.5 before:w-3 before:h-3 before:border-t-2 before:border-l-2 before:border-thv08-orange before:transition-[width,height] before:duration-250 after:content-[''] after:absolute after:-bottom-0.5 after:-right-0.5 after:w-3 after:h-3 after:border-b-2 after:border-r-2 after:border-thv08-orange after:transition-[width,height] after:duration-250 hover:before:w-[calc(100%+4px)] hover:before:h-[calc(100%+4px)] hover:after:w-[calc(100%+4px)] hover:after:h-[calc(100%+4px)] focus-visible:before:w-[calc(100%+4px)] focus-visible:before:h-[calc(100%+4px)] focus-visible:after:w-[calc(100%+4px)] focus-visible:after:h-[calc(100%+4px)] motion-reduce:before:transition-none motion-reduce:after:transition-none">Corner Flash</button>
<span class="text-[11px] tracking-[0.12em] uppercase text-thv08-dim">corner brackets</span>
</div>
<div class="flex flex-col items-center gap-5 px-5 py-10 rounded-xl bg-white/[0.025] border border-white/[0.07]">
<button type="button" class="relative overflow-hidden min-h-11 px-8 py-3 bg-transparent text-[0.95rem] font-semibold tracking-[0.05em] text-thv08-red cursor-pointer transition-colors duration-300 hover:text-thv08-text focus-visible:text-thv08-text focus-visible:outline-2 focus-visible:outline-offset-3 focus-visible:outline-thv08-red before:content-[''] before:absolute before:top-0 before:-left-full before:w-full before:h-0.5 before:bg-thv08-red before:transition-[left] before:duration-350 before:ease-[cubic-bezier(.4,0,.2,1)] after:content-[''] after:absolute after:bottom-0 after:-right-full after:w-full after:h-0.5 after:bg-thv08-red after:transition-[right] after:duration-350 after:ease-[cubic-bezier(.4,0,.2,1)] hover:before:left-0 hover:after:right-0 focus-visible:before:left-0 focus-visible:after:right-0 motion-reduce:before:transition-none motion-reduce:after:transition-none">Double Rail</button>
<span class="text-[11px] tracking-[0.12em] uppercase text-thv08-dim">dual-rail slide</span>
</div>
<div class="flex flex-col items-center gap-5 px-5 py-10 rounded-xl bg-white/[0.025] border border-white/[0.07]">
<button type="button" class="min-h-11 px-8 py-3 bg-transparent border-2 border-dashed border-transparent text-[0.95rem] font-semibold tracking-[0.05em] text-thv08-yellow cursor-pointer transition-[border-color,color,padding] duration-300 hover:border-thv08-yellow hover:text-thv08-text hover:px-10 focus-visible:border-thv08-yellow focus-visible:text-thv08-text focus-visible:outline-2 focus-visible:outline-offset-3 focus-visible:outline-thv08-yellow motion-reduce:transition-[border-color,color] motion-reduce:hover:px-8">Dashed Grow</button>
<span class="text-[11px] tracking-[0.12em] uppercase text-thv08-dim">dashed border scale</span>
</div>
<div class="flex flex-col items-center gap-5 px-5 py-10 rounded-xl bg-white/[0.025] border border-white/[0.07]">
<button type="button" class="relative isolate overflow-visible min-h-11 px-8 py-3 bg-transparent text-[0.95rem] font-semibold tracking-[0.05em] text-thv08-text cursor-pointer focus-visible:outline-2 focus-visible:outline-offset-4 focus-visible:outline-thv08-amber before:content-[''] before:absolute before:-inset-0.5 before:-z-10 before:rounded-[4px] before:opacity-0 before:transition-opacity before:duration-300 before:[--thv08-angle:0deg] before:[background:conic-gradient(from_var(--thv08-angle),transparent_0%,var(--color-thv08-amber)_30%,var(--color-thv08-orange)_50%,transparent_70%)] after:content-[''] after:absolute after:inset-0 after:-z-10 after:rounded-[2px] after:bg-thv08-bg hover:before:opacity-100 hover:before:animate-thv08-spin focus-visible:before:opacity-100 focus-visible:before:animate-thv08-spin motion-reduce:hover:before:animate-none">Gradient Sweep</button>
<span class="text-[11px] tracking-[0.12em] uppercase text-thv08-dim">conic border sweep</span>
</div>
<div class="flex flex-col items-center gap-5 px-5 py-10 rounded-xl bg-white/[0.025] border border-white/[0.07]">
<button type="button" class="min-h-11 px-8 py-3 bg-transparent text-[0.95rem] font-semibold tracking-[0.05em] text-thv08-gold cursor-pointer shadow-[inset_0_0_0_0_var(--color-thv08-amber)] transition-[box-shadow,color] duration-400 ease-[cubic-bezier(.4,0,.2,1)] hover:text-black hover:shadow-[inset_0_0_0_60px_var(--color-thv08-amber)] focus-visible:text-black focus-visible:shadow-[inset_0_0_0_60px_var(--color-thv08-amber)] focus-visible:outline-2 focus-visible:outline-offset-3 focus-visible:outline-thv08-amber motion-reduce:transition-none">Inset Reveal</button>
<span class="text-[11px] tracking-[0.12em] uppercase text-thv08-dim">box-shadow inset</span>
</div>
</div>
</section>@import "tailwindcss";
@theme {
--color-thv08-bg: #0c0a03;
--color-thv08-bg: oklch(0.14 0.02 85);
--color-thv08-text: #fef3c7;
--color-thv08-text: oklch(0.95 0.06 95);
--color-thv08-dim: #6b7280;
--color-thv08-dim: oklch(0.55 0.02 265);
--color-thv08-amber: #f59e0b;
--color-thv08-amber: oklch(0.77 0.16 70);
--color-thv08-orange: #f97316;
--color-thv08-orange: oklch(0.7 0.19 45);
--color-thv08-red: #ef4444;
--color-thv08-red: oklch(0.64 0.21 25);
--color-thv08-yellow: #fde047;
--color-thv08-yellow: oklch(0.91 0.17 99);
--color-thv08-gold: #b45309;
--color-thv08-gold: oklch(0.55 0.14 55);
--font-thv08-sans: 'Space Grotesk', system-ui, sans-serif;
--animate-thv08-spin: thv08-spin 1.5s linear infinite;
}
.thv-08 {
width: 100%;
min-height: 100svh;
}
.thv-08 ::selection {
background: var(--color-thv08-amber);
color: #000;
}
/* A registered custom property: a declaration, not a value — stays in CSS. */
@property --thv08-angle {
syntax: '<angle>';
initial-value: 0deg;
inherits: false;
}
@keyframes thv08-spin {
to {
--thv08-angle: 360deg;
}
}@import "tailwindcss";
@theme {
--color-thv08-bg: #0c0a03;
--color-thv08-bg: oklch(0.14 0.02 85);
--color-thv08-text: #fef3c7;
--color-thv08-text: oklch(0.95 0.06 95);
--color-thv08-dim: #6b7280;
--color-thv08-dim: oklch(0.55 0.02 265);
--color-thv08-amber: #f59e0b;
--color-thv08-amber: oklch(0.77 0.16 70);
--color-thv08-orange: #f97316;
--color-thv08-orange: oklch(0.7 0.19 45);
--color-thv08-red: #ef4444;
--color-thv08-red: oklch(0.64 0.21 25);
--color-thv08-yellow: #fde047;
--color-thv08-yellow: oklch(0.91 0.17 99);
--color-thv08-gold: #b45309;
--color-thv08-gold: oklch(0.55 0.14 55);
--font-thv08-sans: 'Space Grotesk', system-ui, sans-serif;
--animate-thv08-spin: thv08-spin 1.5s linear infinite;
}
.thv-08 {
width: 100%;
min-height: 100svh;
}
.thv-08 ::selection {
background: var(--color-thv08-amber);
color: #000;
}
/* A registered custom property: a declaration, not a value — stays in CSS. */
@property --thv08-angle {
syntax: '<angle>';
initial-value: 0deg;
inherits: false;
}
@keyframes thv08-spin {
to {
--thv08-angle: 360deg;
}
}Setup — do this once per project
Skip this if your project already runs Tailwind v4.
<script src="https://cdn.jsdelivr.net/npm/@tailwindcss/browser@4"></script>
<script src="https://cdn.jsdelivr.net/npm/@tailwindcss/browser@4"></script>Compiles in the browser — perfect for a CodePen or a quick test, not for production.
npm install tailwindcss @tailwindcss/vite
npm install tailwindcss @tailwindcss/vite// vite.config.js ("type": "module" in package.json)
import { defineConfig } from 'vite'
import tailwindcss from '@tailwindcss/vite'
export default defineConfig({
plugins: [tailwindcss()],
})// vite.config.js ("type": "module" in package.json)
import { defineConfig } from 'vite'
import tailwindcss from '@tailwindcss/vite'
export default defineConfig({
plugins: [tailwindcss()],
})Any v4 setup works — Vite, PostCSS or the CLI. Nothing in this demo is bundler-specific.
@import "tailwindcss";
@theme {
--color-thv08-bg: #0c0a03;
--color-thv08-bg: oklch(0.14 0.02 85);
--color-thv08-text: #fef3c7;
--color-thv08-text: oklch(0.95 0.06 95);
--color-thv08-dim: #6b7280;
--color-thv08-dim: oklch(0.55 0.02 265);
--color-thv08-amber: #f59e0b;
--color-thv08-amber: oklch(0.77 0.16 70);
--color-thv08-orange: #f97316;
--color-thv08-orange: oklch(0.7 0.19 45);
--color-thv08-red: #ef4444;
--color-thv08-red: oklch(0.64 0.21 25);
--color-thv08-yellow: #fde047;
--color-thv08-yellow: oklch(0.91 0.17 99);
--color-thv08-gold: #b45309;
--color-thv08-gold: oklch(0.55 0.14 55);
--font-thv08-sans: 'Space Grotesk', system-ui, sans-serif;
--animate-thv08-spin: thv08-spin 1.5s linear infinite;
}
.thv-08 {
width: 100%;
min-height: 100svh;
}
.thv-08 ::selection {
background: var(--color-thv08-amber);
color: #000;
}
/* A registered custom property: a declaration, not a value — stays in CSS. */
@property --thv08-angle {
syntax: '<angle>';
initial-value: 0deg;
inherits: false;
}
@keyframes thv08-spin {
to {
--thv08-angle: 360deg;
}
}@import "tailwindcss";
@theme {
--color-thv08-bg: #0c0a03;
--color-thv08-bg: oklch(0.14 0.02 85);
--color-thv08-text: #fef3c7;
--color-thv08-text: oklch(0.95 0.06 95);
--color-thv08-dim: #6b7280;
--color-thv08-dim: oklch(0.55 0.02 265);
--color-thv08-amber: #f59e0b;
--color-thv08-amber: oklch(0.77 0.16 70);
--color-thv08-orange: #f97316;
--color-thv08-orange: oklch(0.7 0.19 45);
--color-thv08-red: #ef4444;
--color-thv08-red: oklch(0.64 0.21 25);
--color-thv08-yellow: #fde047;
--color-thv08-yellow: oklch(0.91 0.17 99);
--color-thv08-gold: #b45309;
--color-thv08-gold: oklch(0.55 0.14 55);
--font-thv08-sans: 'Space Grotesk', system-ui, sans-serif;
--animate-thv08-spin: thv08-spin 1.5s linear infinite;
}
.thv-08 {
width: 100%;
min-height: 100svh;
}
.thv-08 ::selection {
background: var(--color-thv08-amber);
color: #000;
}
/* A registered custom property: a declaration, not a value — stays in CSS. */
@property --thv08-angle {
syntax: '<angle>';
initial-value: 0deg;
inherits: false;
}
@keyframes thv08-spin {
to {
--thv08-angle: 360deg;
}
}<link rel="preconnect" href="https://fonts.googleapis.com"> <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin> <link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Space+Grotesk:wght@400;500;600;700&family=JetBrains+Mono:wght@400;500;600;800&display=swap">
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Space+Grotesk:wght@400;500;600;700&family=JetBrains+Mono:wght@400;500;600;800&display=swap">What changed in the port
Which parts became utilities, which stayed CSS, and why.
@propertyplus a one-line keyframe stays in the stylesheet; the gradient that reads it is an arbitrary background on the element. That split is the general rule for the whole collection.- UI change from the CSS original: all six are real buttons with
min-h-11, focus rings andfocus-visible:twins, so each border draws for keyboard users too. - The dashed variant's padding jump is cancelled under
motion-reduce:(the colour change remains) — a 8px layout shift is motion, even though it is not an animation.
Here's a working CSS demo from CodeFronts. Use it as-is or adapt to your framework. All classes are scoped under a unique prefix so the code won't collide with your existing styles. MIT licensed.
Demo: Tailwind Border Draw Hover Effect
Source: https://codefronts.com/motion/tailwind-css-hover-effects/tailwind-border-draw-hover-effect/
Six border-draw hovers — clockwise stroke, corner brackets, double rail, dashed grow, a spinning conic ring and an inset box-shadow flood. The conic ring animates a registered --angle rather than rotating the element, which is what keeps a wide rectangle from flailing.
## HTML
```html
<section class="thv-08 w-full min-h-svh grid place-items-center bg-thv08-bg font-thv08-sans px-6 py-14">
<div class="w-[min(880px,100%)] grid grid-cols-[repeat(auto-fit,minmax(230px,1fr))] gap-9">
<div class="flex flex-col items-center gap-5 px-5 py-10 rounded-xl bg-white/[0.025] border border-white/[0.07]">
<button type="button" class="relative min-h-11 px-8 py-3 bg-transparent text-[0.95rem] font-semibold tracking-[0.05em] text-thv08-amber cursor-pointer transition-[color,box-shadow] duration-300 delay-[390ms] hover:text-thv08-text hover:shadow-[inset_2px_0_0_var(--color-thv08-amber),inset_-2px_0_0_var(--color-thv08-amber)] hover:delay-200 focus-visible:text-thv08-text focus-visible:shadow-[inset_2px_0_0_var(--color-thv08-amber),inset_-2px_0_0_var(--color-thv08-amber)] focus-visible:outline-2 focus-visible:outline-offset-3 focus-visible:outline-thv08-amber before:content-[''] before:absolute before:top-0 before:right-0 before:w-0 before:h-0.5 before:bg-thv08-amber before:transition-[width] before:duration-200 after:content-[''] after:absolute after:bottom-0 after:left-0 after:w-0 after:h-0.5 after:bg-thv08-amber after:transition-[width] after:duration-200 after:delay-400 hover:before:w-full hover:after:w-full hover:after:delay-200 focus-visible:before:w-full focus-visible:after:w-full motion-reduce:before:transition-none motion-reduce:after:transition-none">Clockwise Draw</button>
<span class="text-[11px] tracking-[0.12em] uppercase text-thv08-dim">clockwise stroke</span>
</div>
<div class="flex flex-col items-center gap-5 px-5 py-10 rounded-xl bg-white/[0.025] border border-white/[0.07]">
<button type="button" class="relative overflow-visible min-h-11 px-8 py-3 bg-transparent text-[0.95rem] font-semibold tracking-[0.05em] text-thv08-orange cursor-pointer transition-colors duration-300 focus-visible:outline-2 focus-visible:outline-offset-4 focus-visible:outline-thv08-orange before:content-[''] before:absolute before:-top-0.5 before:-left-0.5 before:w-3 before:h-3 before:border-t-2 before:border-l-2 before:border-thv08-orange before:transition-[width,height] before:duration-250 after:content-[''] after:absolute after:-bottom-0.5 after:-right-0.5 after:w-3 after:h-3 after:border-b-2 after:border-r-2 after:border-thv08-orange after:transition-[width,height] after:duration-250 hover:before:w-[calc(100%+4px)] hover:before:h-[calc(100%+4px)] hover:after:w-[calc(100%+4px)] hover:after:h-[calc(100%+4px)] focus-visible:before:w-[calc(100%+4px)] focus-visible:before:h-[calc(100%+4px)] focus-visible:after:w-[calc(100%+4px)] focus-visible:after:h-[calc(100%+4px)] motion-reduce:before:transition-none motion-reduce:after:transition-none">Corner Flash</button>
<span class="text-[11px] tracking-[0.12em] uppercase text-thv08-dim">corner brackets</span>
</div>
<div class="flex flex-col items-center gap-5 px-5 py-10 rounded-xl bg-white/[0.025] border border-white/[0.07]">
<button type="button" class="relative overflow-hidden min-h-11 px-8 py-3 bg-transparent text-[0.95rem] font-semibold tracking-[0.05em] text-thv08-red cursor-pointer transition-colors duration-300 hover:text-thv08-text focus-visible:text-thv08-text focus-visible:outline-2 focus-visible:outline-offset-3 focus-visible:outline-thv08-red before:content-[''] before:absolute before:top-0 before:-left-full before:w-full before:h-0.5 before:bg-thv08-red before:transition-[left] before:duration-350 before:ease-[cubic-bezier(.4,0,.2,1)] after:content-[''] after:absolute after:bottom-0 after:-right-full after:w-full after:h-0.5 after:bg-thv08-red after:transition-[right] after:duration-350 after:ease-[cubic-bezier(.4,0,.2,1)] hover:before:left-0 hover:after:right-0 focus-visible:before:left-0 focus-visible:after:right-0 motion-reduce:before:transition-none motion-reduce:after:transition-none">Double Rail</button>
<span class="text-[11px] tracking-[0.12em] uppercase text-thv08-dim">dual-rail slide</span>
</div>
<div class="flex flex-col items-center gap-5 px-5 py-10 rounded-xl bg-white/[0.025] border border-white/[0.07]">
<button type="button" class="min-h-11 px-8 py-3 bg-transparent border-2 border-dashed border-transparent text-[0.95rem] font-semibold tracking-[0.05em] text-thv08-yellow cursor-pointer transition-[border-color,color,padding] duration-300 hover:border-thv08-yellow hover:text-thv08-text hover:px-10 focus-visible:border-thv08-yellow focus-visible:text-thv08-text focus-visible:outline-2 focus-visible:outline-offset-3 focus-visible:outline-thv08-yellow motion-reduce:transition-[border-color,color] motion-reduce:hover:px-8">Dashed Grow</button>
<span class="text-[11px] tracking-[0.12em] uppercase text-thv08-dim">dashed border scale</span>
</div>
<div class="flex flex-col items-center gap-5 px-5 py-10 rounded-xl bg-white/[0.025] border border-white/[0.07]">
<button type="button" class="relative isolate overflow-visible min-h-11 px-8 py-3 bg-transparent text-[0.95rem] font-semibold tracking-[0.05em] text-thv08-text cursor-pointer focus-visible:outline-2 focus-visible:outline-offset-4 focus-visible:outline-thv08-amber before:content-[''] before:absolute before:-inset-0.5 before:-z-10 before:rounded-[4px] before:opacity-0 before:transition-opacity before:duration-300 before:[--thv08-angle:0deg] before:[background:conic-gradient(from_var(--thv08-angle),transparent_0%,var(--color-thv08-amber)_30%,var(--color-thv08-orange)_50%,transparent_70%)] after:content-[''] after:absolute after:inset-0 after:-z-10 after:rounded-[2px] after:bg-thv08-bg hover:before:opacity-100 hover:before:animate-thv08-spin focus-visible:before:opacity-100 focus-visible:before:animate-thv08-spin motion-reduce:hover:before:animate-none">Gradient Sweep</button>
<span class="text-[11px] tracking-[0.12em] uppercase text-thv08-dim">conic border sweep</span>
</div>
<div class="flex flex-col items-center gap-5 px-5 py-10 rounded-xl bg-white/[0.025] border border-white/[0.07]">
<button type="button" class="min-h-11 px-8 py-3 bg-transparent text-[0.95rem] font-semibold tracking-[0.05em] text-thv08-gold cursor-pointer shadow-[inset_0_0_0_0_var(--color-thv08-amber)] transition-[box-shadow,color] duration-400 ease-[cubic-bezier(.4,0,.2,1)] hover:text-black hover:shadow-[inset_0_0_0_60px_var(--color-thv08-amber)] focus-visible:text-black focus-visible:shadow-[inset_0_0_0_60px_var(--color-thv08-amber)] focus-visible:outline-2 focus-visible:outline-offset-3 focus-visible:outline-thv08-amber motion-reduce:transition-none">Inset Reveal</button>
<span class="text-[11px] tracking-[0.12em] uppercase text-thv08-dim">box-shadow inset</span>
</div>
</div>
</section>
```
## CSS
```css
@import "tailwindcss";
@theme {
--color-thv08-bg: #0c0a03;
--color-thv08-bg: oklch(0.14 0.02 85);
--color-thv08-text: #fef3c7;
--color-thv08-text: oklch(0.95 0.06 95);
--color-thv08-dim: #6b7280;
--color-thv08-dim: oklch(0.55 0.02 265);
--color-thv08-amber: #f59e0b;
--color-thv08-amber: oklch(0.77 0.16 70);
--color-thv08-orange: #f97316;
--color-thv08-orange: oklch(0.7 0.19 45);
--color-thv08-red: #ef4444;
--color-thv08-red: oklch(0.64 0.21 25);
--color-thv08-yellow: #fde047;
--color-thv08-yellow: oklch(0.91 0.17 99);
--color-thv08-gold: #b45309;
--color-thv08-gold: oklch(0.55 0.14 55);
--font-thv08-sans: 'Space Grotesk', system-ui, sans-serif;
--animate-thv08-spin: thv08-spin 1.5s linear infinite;
}
.thv-08 {
width: 100%;
min-height: 100svh;
}
.thv-08 ::selection {
background: var(--color-thv08-amber);
color: #000;
}
/* A registered custom property: a declaration, not a value — stays in CSS. */
@property --thv08-angle {
syntax: '<angle>';
initial-value: 0deg;
inherits: false;
}
@keyframes thv08-spin {
to {
--thv08-angle: 360deg;
}
}
```Here's a working CSS demo from CodeFronts. Use it as-is or adapt to your framework. All classes are scoped under a unique prefix so the code won't collide with your existing styles. MIT licensed.
Demo: Tailwind Border Draw Hover Effect
Source: https://codefronts.com/motion/tailwind-css-hover-effects/tailwind-border-draw-hover-effect/
Six border-draw hovers — clockwise stroke, corner brackets, double rail, dashed grow, a spinning conic ring and an inset box-shadow flood. The conic ring animates a registered --angle rather than rotating the element, which is what keeps a wide rectangle from flailing.
## HTML
```html
<section class="thv-08 w-full min-h-svh grid place-items-center bg-thv08-bg font-thv08-sans px-6 py-14">
<div class="w-[min(880px,100%)] grid grid-cols-[repeat(auto-fit,minmax(230px,1fr))] gap-9">
<div class="flex flex-col items-center gap-5 px-5 py-10 rounded-xl bg-white/[0.025] border border-white/[0.07]">
<button type="button" class="relative min-h-11 px-8 py-3 bg-transparent text-[0.95rem] font-semibold tracking-[0.05em] text-thv08-amber cursor-pointer transition-[color,box-shadow] duration-300 delay-[390ms] hover:text-thv08-text hover:shadow-[inset_2px_0_0_var(--color-thv08-amber),inset_-2px_0_0_var(--color-thv08-amber)] hover:delay-200 focus-visible:text-thv08-text focus-visible:shadow-[inset_2px_0_0_var(--color-thv08-amber),inset_-2px_0_0_var(--color-thv08-amber)] focus-visible:outline-2 focus-visible:outline-offset-3 focus-visible:outline-thv08-amber before:content-[''] before:absolute before:top-0 before:right-0 before:w-0 before:h-0.5 before:bg-thv08-amber before:transition-[width] before:duration-200 after:content-[''] after:absolute after:bottom-0 after:left-0 after:w-0 after:h-0.5 after:bg-thv08-amber after:transition-[width] after:duration-200 after:delay-400 hover:before:w-full hover:after:w-full hover:after:delay-200 focus-visible:before:w-full focus-visible:after:w-full motion-reduce:before:transition-none motion-reduce:after:transition-none">Clockwise Draw</button>
<span class="text-[11px] tracking-[0.12em] uppercase text-thv08-dim">clockwise stroke</span>
</div>
<div class="flex flex-col items-center gap-5 px-5 py-10 rounded-xl bg-white/[0.025] border border-white/[0.07]">
<button type="button" class="relative overflow-visible min-h-11 px-8 py-3 bg-transparent text-[0.95rem] font-semibold tracking-[0.05em] text-thv08-orange cursor-pointer transition-colors duration-300 focus-visible:outline-2 focus-visible:outline-offset-4 focus-visible:outline-thv08-orange before:content-[''] before:absolute before:-top-0.5 before:-left-0.5 before:w-3 before:h-3 before:border-t-2 before:border-l-2 before:border-thv08-orange before:transition-[width,height] before:duration-250 after:content-[''] after:absolute after:-bottom-0.5 after:-right-0.5 after:w-3 after:h-3 after:border-b-2 after:border-r-2 after:border-thv08-orange after:transition-[width,height] after:duration-250 hover:before:w-[calc(100%+4px)] hover:before:h-[calc(100%+4px)] hover:after:w-[calc(100%+4px)] hover:after:h-[calc(100%+4px)] focus-visible:before:w-[calc(100%+4px)] focus-visible:before:h-[calc(100%+4px)] focus-visible:after:w-[calc(100%+4px)] focus-visible:after:h-[calc(100%+4px)] motion-reduce:before:transition-none motion-reduce:after:transition-none">Corner Flash</button>
<span class="text-[11px] tracking-[0.12em] uppercase text-thv08-dim">corner brackets</span>
</div>
<div class="flex flex-col items-center gap-5 px-5 py-10 rounded-xl bg-white/[0.025] border border-white/[0.07]">
<button type="button" class="relative overflow-hidden min-h-11 px-8 py-3 bg-transparent text-[0.95rem] font-semibold tracking-[0.05em] text-thv08-red cursor-pointer transition-colors duration-300 hover:text-thv08-text focus-visible:text-thv08-text focus-visible:outline-2 focus-visible:outline-offset-3 focus-visible:outline-thv08-red before:content-[''] before:absolute before:top-0 before:-left-full before:w-full before:h-0.5 before:bg-thv08-red before:transition-[left] before:duration-350 before:ease-[cubic-bezier(.4,0,.2,1)] after:content-[''] after:absolute after:bottom-0 after:-right-full after:w-full after:h-0.5 after:bg-thv08-red after:transition-[right] after:duration-350 after:ease-[cubic-bezier(.4,0,.2,1)] hover:before:left-0 hover:after:right-0 focus-visible:before:left-0 focus-visible:after:right-0 motion-reduce:before:transition-none motion-reduce:after:transition-none">Double Rail</button>
<span class="text-[11px] tracking-[0.12em] uppercase text-thv08-dim">dual-rail slide</span>
</div>
<div class="flex flex-col items-center gap-5 px-5 py-10 rounded-xl bg-white/[0.025] border border-white/[0.07]">
<button type="button" class="min-h-11 px-8 py-3 bg-transparent border-2 border-dashed border-transparent text-[0.95rem] font-semibold tracking-[0.05em] text-thv08-yellow cursor-pointer transition-[border-color,color,padding] duration-300 hover:border-thv08-yellow hover:text-thv08-text hover:px-10 focus-visible:border-thv08-yellow focus-visible:text-thv08-text focus-visible:outline-2 focus-visible:outline-offset-3 focus-visible:outline-thv08-yellow motion-reduce:transition-[border-color,color] motion-reduce:hover:px-8">Dashed Grow</button>
<span class="text-[11px] tracking-[0.12em] uppercase text-thv08-dim">dashed border scale</span>
</div>
<div class="flex flex-col items-center gap-5 px-5 py-10 rounded-xl bg-white/[0.025] border border-white/[0.07]">
<button type="button" class="relative isolate overflow-visible min-h-11 px-8 py-3 bg-transparent text-[0.95rem] font-semibold tracking-[0.05em] text-thv08-text cursor-pointer focus-visible:outline-2 focus-visible:outline-offset-4 focus-visible:outline-thv08-amber before:content-[''] before:absolute before:-inset-0.5 before:-z-10 before:rounded-[4px] before:opacity-0 before:transition-opacity before:duration-300 before:[--thv08-angle:0deg] before:[background:conic-gradient(from_var(--thv08-angle),transparent_0%,var(--color-thv08-amber)_30%,var(--color-thv08-orange)_50%,transparent_70%)] after:content-[''] after:absolute after:inset-0 after:-z-10 after:rounded-[2px] after:bg-thv08-bg hover:before:opacity-100 hover:before:animate-thv08-spin focus-visible:before:opacity-100 focus-visible:before:animate-thv08-spin motion-reduce:hover:before:animate-none">Gradient Sweep</button>
<span class="text-[11px] tracking-[0.12em] uppercase text-thv08-dim">conic border sweep</span>
</div>
<div class="flex flex-col items-center gap-5 px-5 py-10 rounded-xl bg-white/[0.025] border border-white/[0.07]">
<button type="button" class="min-h-11 px-8 py-3 bg-transparent text-[0.95rem] font-semibold tracking-[0.05em] text-thv08-gold cursor-pointer shadow-[inset_0_0_0_0_var(--color-thv08-amber)] transition-[box-shadow,color] duration-400 ease-[cubic-bezier(.4,0,.2,1)] hover:text-black hover:shadow-[inset_0_0_0_60px_var(--color-thv08-amber)] focus-visible:text-black focus-visible:shadow-[inset_0_0_0_60px_var(--color-thv08-amber)] focus-visible:outline-2 focus-visible:outline-offset-3 focus-visible:outline-thv08-amber motion-reduce:transition-none">Inset Reveal</button>
<span class="text-[11px] tracking-[0.12em] uppercase text-thv08-dim">box-shadow inset</span>
</div>
</div>
</section>
```
## CSS
```css
@import "tailwindcss";
@theme {
--color-thv08-bg: #0c0a03;
--color-thv08-bg: oklch(0.14 0.02 85);
--color-thv08-text: #fef3c7;
--color-thv08-text: oklch(0.95 0.06 95);
--color-thv08-dim: #6b7280;
--color-thv08-dim: oklch(0.55 0.02 265);
--color-thv08-amber: #f59e0b;
--color-thv08-amber: oklch(0.77 0.16 70);
--color-thv08-orange: #f97316;
--color-thv08-orange: oklch(0.7 0.19 45);
--color-thv08-red: #ef4444;
--color-thv08-red: oklch(0.64 0.21 25);
--color-thv08-yellow: #fde047;
--color-thv08-yellow: oklch(0.91 0.17 99);
--color-thv08-gold: #b45309;
--color-thv08-gold: oklch(0.55 0.14 55);
--font-thv08-sans: 'Space Grotesk', system-ui, sans-serif;
--animate-thv08-spin: thv08-spin 1.5s linear infinite;
}
.thv-08 {
width: 100%;
min-height: 100svh;
}
.thv-08 ::selection {
background: var(--color-thv08-amber);
color: #000;
}
/* A registered custom property: a declaration, not a value — stays in CSS. */
@property --thv08-angle {
syntax: '<angle>';
initial-value: 0deg;
inherits: false;
}
@keyframes thv08-spin {
to {
--thv08-angle: 360deg;
}
}
```How this works
Staggering is a utility now. The clockwise draw needs the bottom rail to start after the top rail finishes; in CSS that was a transition shorthand with a delay buried in it. Here it is after:delay-200, visible in the class list.
The conic ring keeps its @property fix. @property --thv08-angle { syntax: '<angle>'; initial-value: 0deg; inherits: false } stays in CSS — it is a registration, not a value — and the keyframe animates the property. The gradient reads conic-gradient(from var(--thv08-angle), ...) inside an arbitrary background, so only the paint rotates.
Per-variant overflow. The shared button style clips; the bracket and ring variants restore overflow-visible on themselves. In CSS that override was easy to lose track of; as a utility it is stated on the element that needs it.
Make it yours
- Draw speed:
before:duration-200per side, withafter:delay-*matched to it. - Show a ghost border before the draw with
shadow-[inset_0_0_0_1px_var(--color-thv08-amber)]/20so the target reads as interactive. - Thicker strokes:
before:h-0.5→before:h-1(and the matching width on vertical rails).
Gotchas — read before shipping
- Pseudo-element rails do not follow
rounded-*corners — keep these variants square, or switch to anoutline. - Two pseudo-elements mean at most two independently drawn sides; the other two come from
shadow-[inset...]. @propertyis Chrome 85+/Safari 16.4+/Firefox 128+. Older engines show a static gradient ring, which still looks deliberate.
Browser support
| Chrome | Safari | Firefox | Edge |
|---|---|---|---|
| 111+ | 16.4+ | 128+ | 111+ |
@property is the gate for the spinning ring; every other variant is Baseline.