02 / 36
All 36 in 36 Tailwind CSS Button Hover Effects
- 01Tailwind Magnetic Ripple Attraction Button Hover Effect
- 02Tailwind Cyberpunk Holographic Glitch Grid Button
- 03Tailwind Frosted Glassmorphism Shimmer Glow Button
- 04Tailwind Organic Blob Morph Button Hover Effect
- 05Tailwind Dual-Line Intersection Border Draw Button
- 06Tailwind Isometric Tactile 3D Depress Button
- 07Tailwind Infinite Sliding Kinetic Marquee Button
- 08Tailwind Chroma Conic Gradient Border Spin Button
- 09Tailwind Minimalist Border & Outline Drawing Hover Effects
- 10Tailwind Modern 3D Skeuomorphic Button Press Effects
- 11Tailwind Neo-Brutalist & Cyberpunk Button Glow Effects
- 12Tailwind Sliding Background Color Wipe Button Effects
- 13Tailwind Liquid Fill & Organic Morphing Button Effects
- 14Tailwind Kinetic Text Flip & Icon Reveal Button Effects
- 15Tailwind Liquid Wave Fill Button Hover Effect
- 16Tailwind Magnetic Border Drift Button
- 17Tailwind Glitch Slice Button Hover Effect
- 18Tailwind Neon Pulse Glow Button Hover Effect
- 19Tailwind Split Reveal Curtain Button Effect
- 20Tailwind Diagonal Shutter Sweep Button Effect
- 21Tailwind Elastic Lift Spring Button Hover Effect
- 22Tailwind Center Underline Draw Link Button Effects
- 23Tailwind 3D Flip Card Button Hover Effect
- 24Tailwind Particle Burst Confetti Button Effect
- 25Tailwind Slide Doors Closing Panel Button Effect
- 26Tailwind Typewriter Retype Terminal Button Effect
- 27Tailwind Hard Shadow Shift Flat Button Effect
- 28Tailwind Material Ripple Wave Button Effect
- 29Tailwind Rainbow Gradient Border Spin Button
- 30Tailwind Morph Shape Silhouette Button Effects
- 31Tailwind Icon Slide In Directional Button Effect
- 32Tailwind Cursor Spotlight Glow Button
- 33Tailwind Stagger Fill Equaliser Button Effect
- 34Tailwind Sunburst Expand Radiant Button Effect
- 35Tailwind 3D Press Plunger Key Button Effect
- 36Tailwind Add-to-Cart Liquid Glass Ripple Button
Tailwind Cyberpunk Holographic Glitch Grid Button
A neon sci-fi CTA for gaming, web3 and dev-tool pages: a holographic grid sits behind the label and, on hover, tears with a hard stepped glitch while a magenta/cyan chromatic split flickers over the text. Four @keyframes stay CSS; every trigger, every layer and every reduced-motion fallback becomes a class.
Untitled UI Pro: 5,000+ React + Tailwind CSS v4 components · from $349 one-time
Untitled UI React · Affiliate link
The code
<div class="tbh-02-group w-full min-h-svh flex flex-wrap">
<section class="tbh-02a flex-[1_1_340px] min-w-[300px] grid place-items-center px-6 py-14 font-tbh02-display bg-tbh02a-bg" aria-label="Cyberpunk glitch grid button">
<button type="button" data-text="Enter grid" class="group/btn relative isolate overflow-hidden cursor-pointer rounded border border-tbh02a-cyan px-10 py-[18px] text-base font-bold uppercase tracking-[0.22em] text-tbh02a-ink bg-tbh02a-panel shadow-[0_0_0_1px_color-mix(in_oklab,var(--color-tbh02a-cyan)_20%,transparent),0_0_24px_-8px_var(--color-tbh02a-cyan)] transition-shadow duration-300 hover:shadow-[0_0_0_1px_var(--color-tbh02a-cyan),0_0_34px_-6px_var(--color-tbh02a-cyan),0_0_34px_-6px_var(--color-tbh02a-mag)] focus-visible:shadow-[0_0_0_1px_var(--color-tbh02a-cyan),0_0_34px_-6px_var(--color-tbh02a-cyan)] focus-visible:outline-3 focus-visible:outline-tbh02a-cyan focus-visible:outline-offset-[3px] after:content-[attr(data-text)] after:absolute after:inset-0 after:grid after:place-items-center after:font-[inherit] after:tracking-[0.22em] after:text-tbh02a-ink after:z-[2] after:opacity-0 after:pointer-events-none after:[text-shadow:2px_0_var(--color-tbh02a-mag),-2px_0_var(--color-tbh02a-cyan)] after:[clip-path:inset(0_0_55%_0)] hover:after:opacity-90 hover:after:animate-tbh02a-glitch motion-reduce:hover:after:animate-none motion-reduce:hover:after:opacity-0">
<span aria-hidden="true" class="absolute inset-0 -z-10 opacity-50 bg-[repeating-linear-gradient(90deg,color-mix(in_oklab,var(--color-tbh02a-cyan)_16%,transparent)_0_1px,transparent_1px_22px),repeating-linear-gradient(0deg,color-mix(in_oklab,var(--color-tbh02a-mag)_14%,transparent)_0_1px,transparent_1px_22px)] transition-opacity duration-300 group-hover/btn:opacity-95 group-hover/btn:animate-tbh02a-tear motion-reduce:group-hover/btn:animate-none"></span>
<span class="relative z-[1]">Enter grid</span>
</button>
</section>
<section class="tbh-02b flex-[1_1_340px] min-w-[300px] grid place-items-center px-6 py-14 font-tbh02-mono bg-tbh02b-bg" aria-label="Cyberpunk scanline button">
<button type="button" class="group/btn relative isolate overflow-hidden cursor-pointer rounded border border-tbh02b-grn px-10 py-[18px] text-base font-bold uppercase tracking-[0.2em] text-tbh02b-grn bg-tbh02b-panel shadow-[0_0_20px_-8px_var(--color-tbh02b-grn)] transition-shadow duration-300 hover:shadow-[0_0_30px_-4px_var(--color-tbh02b-grn),inset_0_0_20px_-6px_var(--color-tbh02b-grn)] focus-visible:shadow-[0_0_30px_-4px_var(--color-tbh02b-grn)] focus-visible:outline-3 focus-visible:outline-tbh02b-grn focus-visible:outline-offset-[3px]">
<span aria-hidden="true" class="absolute inset-0 z-0 opacity-40 bg-[repeating-linear-gradient(0deg,color-mix(in_oklab,var(--color-tbh02b-grn)_14%,transparent)_0_2px,transparent_2px_4px)] transition-opacity duration-300 group-hover/btn:opacity-90 group-hover/btn:animate-tbh02b-roll motion-reduce:group-hover/btn:animate-none"></span>
<span class="relative z-[1] group-hover/btn:animate-tbh02b-jit motion-reduce:group-hover/btn:animate-none">Jack in</span>
</button>
</section>
</div><div class="tbh-02-group w-full min-h-svh flex flex-wrap">
<section class="tbh-02a flex-[1_1_340px] min-w-[300px] grid place-items-center px-6 py-14 font-tbh02-display bg-tbh02a-bg" aria-label="Cyberpunk glitch grid button">
<button type="button" data-text="Enter grid" class="group/btn relative isolate overflow-hidden cursor-pointer rounded border border-tbh02a-cyan px-10 py-[18px] text-base font-bold uppercase tracking-[0.22em] text-tbh02a-ink bg-tbh02a-panel shadow-[0_0_0_1px_color-mix(in_oklab,var(--color-tbh02a-cyan)_20%,transparent),0_0_24px_-8px_var(--color-tbh02a-cyan)] transition-shadow duration-300 hover:shadow-[0_0_0_1px_var(--color-tbh02a-cyan),0_0_34px_-6px_var(--color-tbh02a-cyan),0_0_34px_-6px_var(--color-tbh02a-mag)] focus-visible:shadow-[0_0_0_1px_var(--color-tbh02a-cyan),0_0_34px_-6px_var(--color-tbh02a-cyan)] focus-visible:outline-3 focus-visible:outline-tbh02a-cyan focus-visible:outline-offset-[3px] after:content-[attr(data-text)] after:absolute after:inset-0 after:grid after:place-items-center after:font-[inherit] after:tracking-[0.22em] after:text-tbh02a-ink after:z-[2] after:opacity-0 after:pointer-events-none after:[text-shadow:2px_0_var(--color-tbh02a-mag),-2px_0_var(--color-tbh02a-cyan)] after:[clip-path:inset(0_0_55%_0)] hover:after:opacity-90 hover:after:animate-tbh02a-glitch motion-reduce:hover:after:animate-none motion-reduce:hover:after:opacity-0">
<span aria-hidden="true" class="absolute inset-0 -z-10 opacity-50 bg-[repeating-linear-gradient(90deg,color-mix(in_oklab,var(--color-tbh02a-cyan)_16%,transparent)_0_1px,transparent_1px_22px),repeating-linear-gradient(0deg,color-mix(in_oklab,var(--color-tbh02a-mag)_14%,transparent)_0_1px,transparent_1px_22px)] transition-opacity duration-300 group-hover/btn:opacity-95 group-hover/btn:animate-tbh02a-tear motion-reduce:group-hover/btn:animate-none"></span>
<span class="relative z-[1]">Enter grid</span>
</button>
</section>
<section class="tbh-02b flex-[1_1_340px] min-w-[300px] grid place-items-center px-6 py-14 font-tbh02-mono bg-tbh02b-bg" aria-label="Cyberpunk scanline button">
<button type="button" class="group/btn relative isolate overflow-hidden cursor-pointer rounded border border-tbh02b-grn px-10 py-[18px] text-base font-bold uppercase tracking-[0.2em] text-tbh02b-grn bg-tbh02b-panel shadow-[0_0_20px_-8px_var(--color-tbh02b-grn)] transition-shadow duration-300 hover:shadow-[0_0_30px_-4px_var(--color-tbh02b-grn),inset_0_0_20px_-6px_var(--color-tbh02b-grn)] focus-visible:shadow-[0_0_30px_-4px_var(--color-tbh02b-grn)] focus-visible:outline-3 focus-visible:outline-tbh02b-grn focus-visible:outline-offset-[3px]">
<span aria-hidden="true" class="absolute inset-0 z-0 opacity-40 bg-[repeating-linear-gradient(0deg,color-mix(in_oklab,var(--color-tbh02b-grn)_14%,transparent)_0_2px,transparent_2px_4px)] transition-opacity duration-300 group-hover/btn:opacity-90 group-hover/btn:animate-tbh02b-roll motion-reduce:group-hover/btn:animate-none"></span>
<span class="relative z-[1] group-hover/btn:animate-tbh02b-jit motion-reduce:group-hover/btn:animate-none">Jack in</span>
</button>
</section>
</div>@import "tailwindcss";
@theme {
--color-tbh02a-cyan: #22e3ff;
--color-tbh02a-cyan: oklch(0.85 0.15 210);
--color-tbh02a-mag: #ff2bd6;
--color-tbh02a-mag: oklch(0.7 0.28 330);
--color-tbh02a-ink: #eafcff;
--color-tbh02a-ink: oklch(0.97 0.02 210);
--color-tbh02a-bg: #07060f;
--color-tbh02a-bg: oklch(0.12 0.02 285);
--color-tbh02a-panel: #0d0b1f;
--color-tbh02a-panel: oklch(0.17 0.04 285);
--color-tbh02b-grn: #39ff88;
--color-tbh02b-grn: oklch(0.88 0.22 150);
--color-tbh02b-bg: #04100a;
--color-tbh02b-bg: oklch(0.13 0.03 155);
--color-tbh02b-panel: #07160e;
--color-tbh02b-panel: oklch(0.16 0.04 155);
--font-tbh02-display: 'Chakra Petch', ui-monospace, monospace;
--font-tbh02-mono: 'JetBrains Mono', ui-monospace, monospace;
--animate-tbh02a-tear: tbh02a-tear 0.5s steps(5) infinite;
--animate-tbh02a-glitch: tbh02a-glitch 0.45s steps(4) infinite;
--animate-tbh02b-roll: tbh02b-roll 0.6s steps(6) infinite;
--animate-tbh02b-jit: tbh02b-jit 0.3s steps(3) infinite;
}
/* Stays CSS: four keyframe sets, the one part of this demo with no utility form. */
@keyframes tbh02a-tear {
0% {
background-position: 0 0, 0 0;
}
40% {
background-position: 6px -4px, -5px 3px;
}
70% {
background-position: -4px 5px, 7px -6px;
}
100% {
background-position: 0 0, 0 0;
}
}
@keyframes tbh02a-glitch {
0% {
translate: 0 0;
clip-path: inset(0 0 60% 0);
}
30% {
translate: -3px 1px;
clip-path: inset(50% 0 10% 0);
}
60% {
translate: 3px -1px;
clip-path: inset(20% 0 40% 0);
}
100% {
translate: 0 0;
clip-path: inset(0 0 60% 0);
}
}
@keyframes tbh02b-roll {
to {
background-position: 0 8px;
}
}
@keyframes tbh02b-jit {
0%,
100% {
translate: 0 0;
}
50% {
translate: 1.5px 0;
}
}
.tbh-02-group {
width: 100%;
min-height: 100svh;
}
.tbh-02a,
.tbh-02b {
min-height: 100svh;
}@import "tailwindcss";
@theme {
--color-tbh02a-cyan: #22e3ff;
--color-tbh02a-cyan: oklch(0.85 0.15 210);
--color-tbh02a-mag: #ff2bd6;
--color-tbh02a-mag: oklch(0.7 0.28 330);
--color-tbh02a-ink: #eafcff;
--color-tbh02a-ink: oklch(0.97 0.02 210);
--color-tbh02a-bg: #07060f;
--color-tbh02a-bg: oklch(0.12 0.02 285);
--color-tbh02a-panel: #0d0b1f;
--color-tbh02a-panel: oklch(0.17 0.04 285);
--color-tbh02b-grn: #39ff88;
--color-tbh02b-grn: oklch(0.88 0.22 150);
--color-tbh02b-bg: #04100a;
--color-tbh02b-bg: oklch(0.13 0.03 155);
--color-tbh02b-panel: #07160e;
--color-tbh02b-panel: oklch(0.16 0.04 155);
--font-tbh02-display: 'Chakra Petch', ui-monospace, monospace;
--font-tbh02-mono: 'JetBrains Mono', ui-monospace, monospace;
--animate-tbh02a-tear: tbh02a-tear 0.5s steps(5) infinite;
--animate-tbh02a-glitch: tbh02a-glitch 0.45s steps(4) infinite;
--animate-tbh02b-roll: tbh02b-roll 0.6s steps(6) infinite;
--animate-tbh02b-jit: tbh02b-jit 0.3s steps(3) infinite;
}
/* Stays CSS: four keyframe sets, the one part of this demo with no utility form. */
@keyframes tbh02a-tear {
0% {
background-position: 0 0, 0 0;
}
40% {
background-position: 6px -4px, -5px 3px;
}
70% {
background-position: -4px 5px, 7px -6px;
}
100% {
background-position: 0 0, 0 0;
}
}
@keyframes tbh02a-glitch {
0% {
translate: 0 0;
clip-path: inset(0 0 60% 0);
}
30% {
translate: -3px 1px;
clip-path: inset(50% 0 10% 0);
}
60% {
translate: 3px -1px;
clip-path: inset(20% 0 40% 0);
}
100% {
translate: 0 0;
clip-path: inset(0 0 60% 0);
}
}
@keyframes tbh02b-roll {
to {
background-position: 0 8px;
}
}
@keyframes tbh02b-jit {
0%,
100% {
translate: 0 0;
}
50% {
translate: 1.5px 0;
}
}
.tbh-02-group {
width: 100%;
min-height: 100svh;
}
.tbh-02a,
.tbh-02b {
min-height: 100svh;
}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-tbh02a-cyan: #22e3ff;
--color-tbh02a-cyan: oklch(0.85 0.15 210);
--color-tbh02a-mag: #ff2bd6;
--color-tbh02a-mag: oklch(0.7 0.28 330);
--color-tbh02a-ink: #eafcff;
--color-tbh02a-ink: oklch(0.97 0.02 210);
--color-tbh02a-bg: #07060f;
--color-tbh02a-bg: oklch(0.12 0.02 285);
--color-tbh02a-panel: #0d0b1f;
--color-tbh02a-panel: oklch(0.17 0.04 285);
--color-tbh02b-grn: #39ff88;
--color-tbh02b-grn: oklch(0.88 0.22 150);
--color-tbh02b-bg: #04100a;
--color-tbh02b-bg: oklch(0.13 0.03 155);
--color-tbh02b-panel: #07160e;
--color-tbh02b-panel: oklch(0.16 0.04 155);
--font-tbh02-display: 'Chakra Petch', ui-monospace, monospace;
--font-tbh02-mono: 'JetBrains Mono', ui-monospace, monospace;
--animate-tbh02a-tear: tbh02a-tear 0.5s steps(5) infinite;
--animate-tbh02a-glitch: tbh02a-glitch 0.45s steps(4) infinite;
--animate-tbh02b-roll: tbh02b-roll 0.6s steps(6) infinite;
--animate-tbh02b-jit: tbh02b-jit 0.3s steps(3) infinite;
}
/* Stays CSS: four keyframe sets, the one part of this demo with no utility form. */
@keyframes tbh02a-tear {
0% {
background-position: 0 0, 0 0;
}
40% {
background-position: 6px -4px, -5px 3px;
}
70% {
background-position: -4px 5px, 7px -6px;
}
100% {
background-position: 0 0, 0 0;
}
}
@keyframes tbh02a-glitch {
0% {
translate: 0 0;
clip-path: inset(0 0 60% 0);
}
30% {
translate: -3px 1px;
clip-path: inset(50% 0 10% 0);
}
60% {
translate: 3px -1px;
clip-path: inset(20% 0 40% 0);
}
100% {
translate: 0 0;
clip-path: inset(0 0 60% 0);
}
}
@keyframes tbh02b-roll {
to {
background-position: 0 8px;
}
}
@keyframes tbh02b-jit {
0%,
100% {
translate: 0 0;
}
50% {
translate: 1.5px 0;
}
}
.tbh-02-group {
width: 100%;
min-height: 100svh;
}
.tbh-02a,
.tbh-02b {
min-height: 100svh;
}@import "tailwindcss";
@theme {
--color-tbh02a-cyan: #22e3ff;
--color-tbh02a-cyan: oklch(0.85 0.15 210);
--color-tbh02a-mag: #ff2bd6;
--color-tbh02a-mag: oklch(0.7 0.28 330);
--color-tbh02a-ink: #eafcff;
--color-tbh02a-ink: oklch(0.97 0.02 210);
--color-tbh02a-bg: #07060f;
--color-tbh02a-bg: oklch(0.12 0.02 285);
--color-tbh02a-panel: #0d0b1f;
--color-tbh02a-panel: oklch(0.17 0.04 285);
--color-tbh02b-grn: #39ff88;
--color-tbh02b-grn: oklch(0.88 0.22 150);
--color-tbh02b-bg: #04100a;
--color-tbh02b-bg: oklch(0.13 0.03 155);
--color-tbh02b-panel: #07160e;
--color-tbh02b-panel: oklch(0.16 0.04 155);
--font-tbh02-display: 'Chakra Petch', ui-monospace, monospace;
--font-tbh02-mono: 'JetBrains Mono', ui-monospace, monospace;
--animate-tbh02a-tear: tbh02a-tear 0.5s steps(5) infinite;
--animate-tbh02a-glitch: tbh02a-glitch 0.45s steps(4) infinite;
--animate-tbh02b-roll: tbh02b-roll 0.6s steps(6) infinite;
--animate-tbh02b-jit: tbh02b-jit 0.3s steps(3) infinite;
}
/* Stays CSS: four keyframe sets, the one part of this demo with no utility form. */
@keyframes tbh02a-tear {
0% {
background-position: 0 0, 0 0;
}
40% {
background-position: 6px -4px, -5px 3px;
}
70% {
background-position: -4px 5px, 7px -6px;
}
100% {
background-position: 0 0, 0 0;
}
}
@keyframes tbh02a-glitch {
0% {
translate: 0 0;
clip-path: inset(0 0 60% 0);
}
30% {
translate: -3px 1px;
clip-path: inset(50% 0 10% 0);
}
60% {
translate: 3px -1px;
clip-path: inset(20% 0 40% 0);
}
100% {
translate: 0 0;
clip-path: inset(0 0 60% 0);
}
}
@keyframes tbh02b-roll {
to {
background-position: 0 8px;
}
}
@keyframes tbh02b-jit {
0%,
100% {
translate: 0 0;
}
50% {
translate: 1.5px 0;
}
}
.tbh-02-group {
width: 100%;
min-height: 100svh;
}
.tbh-02a,
.tbh-02b {
min-height: 100svh;
}<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=Chakra+Petch:wght@500;600;700&family=JetBrains+Mono:wght@400;500;700&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=Chakra+Petch:wght@500;600;700&family=JetBrains+Mono:wght@400;500;700&display=swap">What changed in the port
Which parts became utilities, which stayed CSS, and why.
- Four
@keyframesstayed CSS, but each gained an@themetoken, so the markup saysanimate-tbh02a-tearinstead of a shorthand no reader can decode. That is the collection's usual split: timing functions and keyframes are CSS, triggers and fallbacks are utilities. - The glitch keyframes now write
translate: -3px 1pxrather thantransform: translate(-3px,1px), so they cannot collide with a transform utility on the same element — a small but real robustness gain from v4's discrete transform properties. - UI change from the CSS original: hover box-shadows are now transitioned (
transition-shadow duration-300) instead of snapping, the focus ring gets its own glow, and reduced motion hides the chromatic layer entirely rather than freezing it mid-split.
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 Cyberpunk Holographic Glitch Grid Button
Source: https://codefronts.com/motion/tailwind-css-button-hover-effects/tailwind-cyberpunk-holographic-glitch-grid-button/
A neon sci-fi CTA for gaming, web3 and dev-tool pages: a holographic grid sits behind the label and, on hover, tears with a hard stepped glitch while a magenta/cyan chromatic split flickers over the text. Four @keyframes stay CSS; every trigger, every layer and every reduced-motion fallback becomes a class.
## HTML
```html
<div class="tbh-02-group w-full min-h-svh flex flex-wrap">
<section class="tbh-02a flex-[1_1_340px] min-w-[300px] grid place-items-center px-6 py-14 font-tbh02-display bg-tbh02a-bg" aria-label="Cyberpunk glitch grid button">
<button type="button" data-text="Enter grid" class="group/btn relative isolate overflow-hidden cursor-pointer rounded border border-tbh02a-cyan px-10 py-[18px] text-base font-bold uppercase tracking-[0.22em] text-tbh02a-ink bg-tbh02a-panel shadow-[0_0_0_1px_color-mix(in_oklab,var(--color-tbh02a-cyan)_20%,transparent),0_0_24px_-8px_var(--color-tbh02a-cyan)] transition-shadow duration-300 hover:shadow-[0_0_0_1px_var(--color-tbh02a-cyan),0_0_34px_-6px_var(--color-tbh02a-cyan),0_0_34px_-6px_var(--color-tbh02a-mag)] focus-visible:shadow-[0_0_0_1px_var(--color-tbh02a-cyan),0_0_34px_-6px_var(--color-tbh02a-cyan)] focus-visible:outline-3 focus-visible:outline-tbh02a-cyan focus-visible:outline-offset-[3px] after:content-[attr(data-text)] after:absolute after:inset-0 after:grid after:place-items-center after:font-[inherit] after:tracking-[0.22em] after:text-tbh02a-ink after:z-[2] after:opacity-0 after:pointer-events-none after:[text-shadow:2px_0_var(--color-tbh02a-mag),-2px_0_var(--color-tbh02a-cyan)] after:[clip-path:inset(0_0_55%_0)] hover:after:opacity-90 hover:after:animate-tbh02a-glitch motion-reduce:hover:after:animate-none motion-reduce:hover:after:opacity-0">
<span aria-hidden="true" class="absolute inset-0 -z-10 opacity-50 bg-[repeating-linear-gradient(90deg,color-mix(in_oklab,var(--color-tbh02a-cyan)_16%,transparent)_0_1px,transparent_1px_22px),repeating-linear-gradient(0deg,color-mix(in_oklab,var(--color-tbh02a-mag)_14%,transparent)_0_1px,transparent_1px_22px)] transition-opacity duration-300 group-hover/btn:opacity-95 group-hover/btn:animate-tbh02a-tear motion-reduce:group-hover/btn:animate-none"></span>
<span class="relative z-[1]">Enter grid</span>
</button>
</section>
<section class="tbh-02b flex-[1_1_340px] min-w-[300px] grid place-items-center px-6 py-14 font-tbh02-mono bg-tbh02b-bg" aria-label="Cyberpunk scanline button">
<button type="button" class="group/btn relative isolate overflow-hidden cursor-pointer rounded border border-tbh02b-grn px-10 py-[18px] text-base font-bold uppercase tracking-[0.2em] text-tbh02b-grn bg-tbh02b-panel shadow-[0_0_20px_-8px_var(--color-tbh02b-grn)] transition-shadow duration-300 hover:shadow-[0_0_30px_-4px_var(--color-tbh02b-grn),inset_0_0_20px_-6px_var(--color-tbh02b-grn)] focus-visible:shadow-[0_0_30px_-4px_var(--color-tbh02b-grn)] focus-visible:outline-3 focus-visible:outline-tbh02b-grn focus-visible:outline-offset-[3px]">
<span aria-hidden="true" class="absolute inset-0 z-0 opacity-40 bg-[repeating-linear-gradient(0deg,color-mix(in_oklab,var(--color-tbh02b-grn)_14%,transparent)_0_2px,transparent_2px_4px)] transition-opacity duration-300 group-hover/btn:opacity-90 group-hover/btn:animate-tbh02b-roll motion-reduce:group-hover/btn:animate-none"></span>
<span class="relative z-[1] group-hover/btn:animate-tbh02b-jit motion-reduce:group-hover/btn:animate-none">Jack in</span>
</button>
</section>
</div>
```
## CSS
```css
@import "tailwindcss";
@theme {
--color-tbh02a-cyan: #22e3ff;
--color-tbh02a-cyan: oklch(0.85 0.15 210);
--color-tbh02a-mag: #ff2bd6;
--color-tbh02a-mag: oklch(0.7 0.28 330);
--color-tbh02a-ink: #eafcff;
--color-tbh02a-ink: oklch(0.97 0.02 210);
--color-tbh02a-bg: #07060f;
--color-tbh02a-bg: oklch(0.12 0.02 285);
--color-tbh02a-panel: #0d0b1f;
--color-tbh02a-panel: oklch(0.17 0.04 285);
--color-tbh02b-grn: #39ff88;
--color-tbh02b-grn: oklch(0.88 0.22 150);
--color-tbh02b-bg: #04100a;
--color-tbh02b-bg: oklch(0.13 0.03 155);
--color-tbh02b-panel: #07160e;
--color-tbh02b-panel: oklch(0.16 0.04 155);
--font-tbh02-display: 'Chakra Petch', ui-monospace, monospace;
--font-tbh02-mono: 'JetBrains Mono', ui-monospace, monospace;
--animate-tbh02a-tear: tbh02a-tear 0.5s steps(5) infinite;
--animate-tbh02a-glitch: tbh02a-glitch 0.45s steps(4) infinite;
--animate-tbh02b-roll: tbh02b-roll 0.6s steps(6) infinite;
--animate-tbh02b-jit: tbh02b-jit 0.3s steps(3) infinite;
}
/* Stays CSS: four keyframe sets, the one part of this demo with no utility form. */
@keyframes tbh02a-tear {
0% {
background-position: 0 0, 0 0;
}
40% {
background-position: 6px -4px, -5px 3px;
}
70% {
background-position: -4px 5px, 7px -6px;
}
100% {
background-position: 0 0, 0 0;
}
}
@keyframes tbh02a-glitch {
0% {
translate: 0 0;
clip-path: inset(0 0 60% 0);
}
30% {
translate: -3px 1px;
clip-path: inset(50% 0 10% 0);
}
60% {
translate: 3px -1px;
clip-path: inset(20% 0 40% 0);
}
100% {
translate: 0 0;
clip-path: inset(0 0 60% 0);
}
}
@keyframes tbh02b-roll {
to {
background-position: 0 8px;
}
}
@keyframes tbh02b-jit {
0%,
100% {
translate: 0 0;
}
50% {
translate: 1.5px 0;
}
}
.tbh-02-group {
width: 100%;
min-height: 100svh;
}
.tbh-02a,
.tbh-02b {
min-height: 100svh;
}
```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 Cyberpunk Holographic Glitch Grid Button
Source: https://codefronts.com/motion/tailwind-css-button-hover-effects/tailwind-cyberpunk-holographic-glitch-grid-button/
A neon sci-fi CTA for gaming, web3 and dev-tool pages: a holographic grid sits behind the label and, on hover, tears with a hard stepped glitch while a magenta/cyan chromatic split flickers over the text. Four @keyframes stay CSS; every trigger, every layer and every reduced-motion fallback becomes a class.
## HTML
```html
<div class="tbh-02-group w-full min-h-svh flex flex-wrap">
<section class="tbh-02a flex-[1_1_340px] min-w-[300px] grid place-items-center px-6 py-14 font-tbh02-display bg-tbh02a-bg" aria-label="Cyberpunk glitch grid button">
<button type="button" data-text="Enter grid" class="group/btn relative isolate overflow-hidden cursor-pointer rounded border border-tbh02a-cyan px-10 py-[18px] text-base font-bold uppercase tracking-[0.22em] text-tbh02a-ink bg-tbh02a-panel shadow-[0_0_0_1px_color-mix(in_oklab,var(--color-tbh02a-cyan)_20%,transparent),0_0_24px_-8px_var(--color-tbh02a-cyan)] transition-shadow duration-300 hover:shadow-[0_0_0_1px_var(--color-tbh02a-cyan),0_0_34px_-6px_var(--color-tbh02a-cyan),0_0_34px_-6px_var(--color-tbh02a-mag)] focus-visible:shadow-[0_0_0_1px_var(--color-tbh02a-cyan),0_0_34px_-6px_var(--color-tbh02a-cyan)] focus-visible:outline-3 focus-visible:outline-tbh02a-cyan focus-visible:outline-offset-[3px] after:content-[attr(data-text)] after:absolute after:inset-0 after:grid after:place-items-center after:font-[inherit] after:tracking-[0.22em] after:text-tbh02a-ink after:z-[2] after:opacity-0 after:pointer-events-none after:[text-shadow:2px_0_var(--color-tbh02a-mag),-2px_0_var(--color-tbh02a-cyan)] after:[clip-path:inset(0_0_55%_0)] hover:after:opacity-90 hover:after:animate-tbh02a-glitch motion-reduce:hover:after:animate-none motion-reduce:hover:after:opacity-0">
<span aria-hidden="true" class="absolute inset-0 -z-10 opacity-50 bg-[repeating-linear-gradient(90deg,color-mix(in_oklab,var(--color-tbh02a-cyan)_16%,transparent)_0_1px,transparent_1px_22px),repeating-linear-gradient(0deg,color-mix(in_oklab,var(--color-tbh02a-mag)_14%,transparent)_0_1px,transparent_1px_22px)] transition-opacity duration-300 group-hover/btn:opacity-95 group-hover/btn:animate-tbh02a-tear motion-reduce:group-hover/btn:animate-none"></span>
<span class="relative z-[1]">Enter grid</span>
</button>
</section>
<section class="tbh-02b flex-[1_1_340px] min-w-[300px] grid place-items-center px-6 py-14 font-tbh02-mono bg-tbh02b-bg" aria-label="Cyberpunk scanline button">
<button type="button" class="group/btn relative isolate overflow-hidden cursor-pointer rounded border border-tbh02b-grn px-10 py-[18px] text-base font-bold uppercase tracking-[0.2em] text-tbh02b-grn bg-tbh02b-panel shadow-[0_0_20px_-8px_var(--color-tbh02b-grn)] transition-shadow duration-300 hover:shadow-[0_0_30px_-4px_var(--color-tbh02b-grn),inset_0_0_20px_-6px_var(--color-tbh02b-grn)] focus-visible:shadow-[0_0_30px_-4px_var(--color-tbh02b-grn)] focus-visible:outline-3 focus-visible:outline-tbh02b-grn focus-visible:outline-offset-[3px]">
<span aria-hidden="true" class="absolute inset-0 z-0 opacity-40 bg-[repeating-linear-gradient(0deg,color-mix(in_oklab,var(--color-tbh02b-grn)_14%,transparent)_0_2px,transparent_2px_4px)] transition-opacity duration-300 group-hover/btn:opacity-90 group-hover/btn:animate-tbh02b-roll motion-reduce:group-hover/btn:animate-none"></span>
<span class="relative z-[1] group-hover/btn:animate-tbh02b-jit motion-reduce:group-hover/btn:animate-none">Jack in</span>
</button>
</section>
</div>
```
## CSS
```css
@import "tailwindcss";
@theme {
--color-tbh02a-cyan: #22e3ff;
--color-tbh02a-cyan: oklch(0.85 0.15 210);
--color-tbh02a-mag: #ff2bd6;
--color-tbh02a-mag: oklch(0.7 0.28 330);
--color-tbh02a-ink: #eafcff;
--color-tbh02a-ink: oklch(0.97 0.02 210);
--color-tbh02a-bg: #07060f;
--color-tbh02a-bg: oklch(0.12 0.02 285);
--color-tbh02a-panel: #0d0b1f;
--color-tbh02a-panel: oklch(0.17 0.04 285);
--color-tbh02b-grn: #39ff88;
--color-tbh02b-grn: oklch(0.88 0.22 150);
--color-tbh02b-bg: #04100a;
--color-tbh02b-bg: oklch(0.13 0.03 155);
--color-tbh02b-panel: #07160e;
--color-tbh02b-panel: oklch(0.16 0.04 155);
--font-tbh02-display: 'Chakra Petch', ui-monospace, monospace;
--font-tbh02-mono: 'JetBrains Mono', ui-monospace, monospace;
--animate-tbh02a-tear: tbh02a-tear 0.5s steps(5) infinite;
--animate-tbh02a-glitch: tbh02a-glitch 0.45s steps(4) infinite;
--animate-tbh02b-roll: tbh02b-roll 0.6s steps(6) infinite;
--animate-tbh02b-jit: tbh02b-jit 0.3s steps(3) infinite;
}
/* Stays CSS: four keyframe sets, the one part of this demo with no utility form. */
@keyframes tbh02a-tear {
0% {
background-position: 0 0, 0 0;
}
40% {
background-position: 6px -4px, -5px 3px;
}
70% {
background-position: -4px 5px, 7px -6px;
}
100% {
background-position: 0 0, 0 0;
}
}
@keyframes tbh02a-glitch {
0% {
translate: 0 0;
clip-path: inset(0 0 60% 0);
}
30% {
translate: -3px 1px;
clip-path: inset(50% 0 10% 0);
}
60% {
translate: 3px -1px;
clip-path: inset(20% 0 40% 0);
}
100% {
translate: 0 0;
clip-path: inset(0 0 60% 0);
}
}
@keyframes tbh02b-roll {
to {
background-position: 0 8px;
}
}
@keyframes tbh02b-jit {
0%,
100% {
translate: 0 0;
}
50% {
translate: 1.5px 0;
}
}
.tbh-02-group {
width: 100%;
min-height: 100svh;
}
.tbh-02a,
.tbh-02b {
min-height: 100svh;
}
```How this works
What has to stay CSS. @keyframes cannot be expressed as a utility, so all four live in the stylesheet. What Tailwind takes over is everything around them: which element animates, on what signal, and what happens under reduced motion. The keyframe becomes a named token, and animate-tbh02a-tear reads as a design decision rather than a shorthand.
The stepped tear is the whole aesthetic. steps(5) in the token snaps the grid's background-position between four offsets instead of easing through them, which is what makes it read as signal loss rather than motion.
The glitch layer is generated, not authored. after:content-[attr(data-text)] pulls the label from the button's own attribute, so the visible copy and the glitch copy cannot drift. The real label sits underneath at full opacity and solid colour, so the accessible text is never the flickering one.
Make it yours
- Neon hues: the two
@themecolour tokens per design — border, glow, grid and text-shadow all read them. - Grid density: the
22pxpitch in the repeating-linear-gradient, and4pxfor design B's scanlines. - Tear violence: the
steps(5)count and.5sduration in the animation token. - Calmer variant: delete
group-hover/btn:animate-tbh02a-tearand keep the opacity lift — the grid still brightens on hover.
Gotchas — read before shipping
- The accessible label must keep a solid colour and sit above the glitch layer, or the button becomes unreadable mid-tear.
- The
after:glitch copy needspointer-events-noneand stays out of the accessibility tree by being a pseudo-element — do not build it as a real duplicated<span>. steps()jumps are harsh by design; themotion-reduce:twins here setanimate-noneAND drop the glitch layer's opacity to 0, because a frozen chromatic split still looks like a rendering bug.- Arbitrary background values cannot contain spaces: every space inside the gradients is an underscore, and the comma between the two layers is real.
Browser support
| Chrome | Safari | Firefox | Edge |
|---|---|---|---|
| 111+ | 16.4+ | 128+ | 111+ |
repeating-linear-gradient, steps(), clip-path and attr() in content are all Baseline; the demo degrades to a solid neon-bordered CTA if the gradients fail.