11 / 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 Neo-Brutalist & Cyberpunk Button Glow Effects
A loud neo-brutalist CTA: flat fill, thick solid border and a hard blur-free offset shadow. On hover it snaps onto its shadow and the shadow flips to saturated neon — a hard, instant snap, not a soft glow. The port makes the effect's one invariant visible: the snap distance and the shadow offset are the same number.
Untitled UI Pro: 5,000+ React + Tailwind CSS v4 components · from $349 one-time
Untitled UI React · Affiliate link
The code
<div class="tbh-11-group w-full min-h-svh flex flex-wrap">
<section class="tbh-11a flex-[1_1_340px] min-w-[300px] grid place-items-center px-6 py-14 font-tbh11-sans bg-tbh11a-stage" aria-label="Neo-brutalist neon button">
<button type="button" class="cursor-pointer rounded-none border-[3px] border-tbh11-ink px-[38px] py-[17px] text-[17px] font-extrabold uppercase tracking-[0.02em] text-tbh11-ink bg-white shadow-[7px_7px_0_var(--color-tbh11-ink)] transition-[translate,scale,box-shadow] duration-[120ms] ease-out hover:translate-x-[7px] hover:translate-y-[7px] hover:shadow-[0_0_0_var(--color-tbh11-ink),0_0_22px_2px_var(--color-tbh11a-mag),0_0_34px_6px_color-mix(in_oklab,var(--color-tbh11a-cyan)_70%,transparent)] focus-visible:translate-x-[7px] focus-visible:translate-y-[7px] focus-visible:shadow-[0_0_0_var(--color-tbh11-ink),0_0_22px_2px_var(--color-tbh11a-mag)] active:scale-[.98] focus-visible:outline-3 focus-visible:outline-tbh11-ink focus-visible:outline-offset-[5px] motion-reduce:transition-[box-shadow] motion-reduce:hover:translate-x-0 motion-reduce:hover:translate-y-0">
Subscribe
</button>
</section>
<section class="tbh-11b flex-[1_1_340px] min-w-[300px] grid place-items-center px-6 py-14 font-tbh11-sans bg-tbh11b-stage" aria-label="Brutalist sticker button">
<button type="button" class="cursor-pointer rounded-[10px] border-[3px] border-tbh11-ink px-10 py-[17px] text-[17px] font-extrabold uppercase text-tbh11-ink bg-tbh11b-lime shadow-[-6px_6px_0_var(--color-tbh11-ink)] transition-[translate,scale,box-shadow,background-color] duration-[120ms] ease-out hover:-translate-x-[6px] hover:translate-y-[6px] hover:bg-tbh11b-hot hover:shadow-[0_0_0_var(--color-tbh11-ink)] focus-visible:-translate-x-[6px] focus-visible:translate-y-[6px] focus-visible:bg-tbh11b-hot focus-visible:shadow-[0_0_0_var(--color-tbh11-ink)] active:scale-[.98] focus-visible:outline-3 focus-visible:outline-white focus-visible:outline-offset-[5px] motion-reduce:transition-[background-color,box-shadow] motion-reduce:hover:translate-x-0 motion-reduce:hover:translate-y-0">
Get access
</button>
</section>
</div><div class="tbh-11-group w-full min-h-svh flex flex-wrap">
<section class="tbh-11a flex-[1_1_340px] min-w-[300px] grid place-items-center px-6 py-14 font-tbh11-sans bg-tbh11a-stage" aria-label="Neo-brutalist neon button">
<button type="button" class="cursor-pointer rounded-none border-[3px] border-tbh11-ink px-[38px] py-[17px] text-[17px] font-extrabold uppercase tracking-[0.02em] text-tbh11-ink bg-white shadow-[7px_7px_0_var(--color-tbh11-ink)] transition-[translate,scale,box-shadow] duration-[120ms] ease-out hover:translate-x-[7px] hover:translate-y-[7px] hover:shadow-[0_0_0_var(--color-tbh11-ink),0_0_22px_2px_var(--color-tbh11a-mag),0_0_34px_6px_color-mix(in_oklab,var(--color-tbh11a-cyan)_70%,transparent)] focus-visible:translate-x-[7px] focus-visible:translate-y-[7px] focus-visible:shadow-[0_0_0_var(--color-tbh11-ink),0_0_22px_2px_var(--color-tbh11a-mag)] active:scale-[.98] focus-visible:outline-3 focus-visible:outline-tbh11-ink focus-visible:outline-offset-[5px] motion-reduce:transition-[box-shadow] motion-reduce:hover:translate-x-0 motion-reduce:hover:translate-y-0">
Subscribe
</button>
</section>
<section class="tbh-11b flex-[1_1_340px] min-w-[300px] grid place-items-center px-6 py-14 font-tbh11-sans bg-tbh11b-stage" aria-label="Brutalist sticker button">
<button type="button" class="cursor-pointer rounded-[10px] border-[3px] border-tbh11-ink px-10 py-[17px] text-[17px] font-extrabold uppercase text-tbh11-ink bg-tbh11b-lime shadow-[-6px_6px_0_var(--color-tbh11-ink)] transition-[translate,scale,box-shadow,background-color] duration-[120ms] ease-out hover:-translate-x-[6px] hover:translate-y-[6px] hover:bg-tbh11b-hot hover:shadow-[0_0_0_var(--color-tbh11-ink)] focus-visible:-translate-x-[6px] focus-visible:translate-y-[6px] focus-visible:bg-tbh11b-hot focus-visible:shadow-[0_0_0_var(--color-tbh11-ink)] active:scale-[.98] focus-visible:outline-3 focus-visible:outline-white focus-visible:outline-offset-[5px] motion-reduce:transition-[background-color,box-shadow] motion-reduce:hover:translate-x-0 motion-reduce:hover:translate-y-0">
Get access
</button>
</section>
</div>@import "tailwindcss";
@theme {
--color-tbh11-ink: #111111;
--color-tbh11-ink: oklch(0.15 0 0);
--color-tbh11a-stage: #f5e94a;
--color-tbh11a-stage: oklch(0.92 0.18 100);
--color-tbh11a-mag: #ff2bd6;
--color-tbh11a-mag: oklch(0.7 0.28 330);
--color-tbh11a-cyan: #22e3ff;
--color-tbh11a-cyan: oklch(0.85 0.15 210);
--color-tbh11b-stage: #111111;
--color-tbh11b-stage: oklch(0.15 0 0);
--color-tbh11b-lime: #4df08a;
--color-tbh11b-lime: oklch(0.85 0.2 150);
--color-tbh11b-hot: #ffe14d;
--color-tbh11b-hot: oklch(0.91 0.17 95);
--font-tbh11-sans: 'Space Grotesk', ui-monospace, sans-serif;
}
/* Nothing stays CSS: two shadow stacks, two translates, one colour flip. */
.tbh-11-group {
width: 100%;
min-height: 100svh;
}
.tbh-11a,
.tbh-11b {
min-height: 100svh;
}@import "tailwindcss";
@theme {
--color-tbh11-ink: #111111;
--color-tbh11-ink: oklch(0.15 0 0);
--color-tbh11a-stage: #f5e94a;
--color-tbh11a-stage: oklch(0.92 0.18 100);
--color-tbh11a-mag: #ff2bd6;
--color-tbh11a-mag: oklch(0.7 0.28 330);
--color-tbh11a-cyan: #22e3ff;
--color-tbh11a-cyan: oklch(0.85 0.15 210);
--color-tbh11b-stage: #111111;
--color-tbh11b-stage: oklch(0.15 0 0);
--color-tbh11b-lime: #4df08a;
--color-tbh11b-lime: oklch(0.85 0.2 150);
--color-tbh11b-hot: #ffe14d;
--color-tbh11b-hot: oklch(0.91 0.17 95);
--font-tbh11-sans: 'Space Grotesk', ui-monospace, sans-serif;
}
/* Nothing stays CSS: two shadow stacks, two translates, one colour flip. */
.tbh-11-group {
width: 100%;
min-height: 100svh;
}
.tbh-11a,
.tbh-11b {
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-tbh11-ink: #111111;
--color-tbh11-ink: oklch(0.15 0 0);
--color-tbh11a-stage: #f5e94a;
--color-tbh11a-stage: oklch(0.92 0.18 100);
--color-tbh11a-mag: #ff2bd6;
--color-tbh11a-mag: oklch(0.7 0.28 330);
--color-tbh11a-cyan: #22e3ff;
--color-tbh11a-cyan: oklch(0.85 0.15 210);
--color-tbh11b-stage: #111111;
--color-tbh11b-stage: oklch(0.15 0 0);
--color-tbh11b-lime: #4df08a;
--color-tbh11b-lime: oklch(0.85 0.2 150);
--color-tbh11b-hot: #ffe14d;
--color-tbh11b-hot: oklch(0.91 0.17 95);
--font-tbh11-sans: 'Space Grotesk', ui-monospace, sans-serif;
}
/* Nothing stays CSS: two shadow stacks, two translates, one colour flip. */
.tbh-11-group {
width: 100%;
min-height: 100svh;
}
.tbh-11a,
.tbh-11b {
min-height: 100svh;
}@import "tailwindcss";
@theme {
--color-tbh11-ink: #111111;
--color-tbh11-ink: oklch(0.15 0 0);
--color-tbh11a-stage: #f5e94a;
--color-tbh11a-stage: oklch(0.92 0.18 100);
--color-tbh11a-mag: #ff2bd6;
--color-tbh11a-mag: oklch(0.7 0.28 330);
--color-tbh11a-cyan: #22e3ff;
--color-tbh11a-cyan: oklch(0.85 0.15 210);
--color-tbh11b-stage: #111111;
--color-tbh11b-stage: oklch(0.15 0 0);
--color-tbh11b-lime: #4df08a;
--color-tbh11b-lime: oklch(0.85 0.2 150);
--color-tbh11b-hot: #ffe14d;
--color-tbh11b-hot: oklch(0.91 0.17 95);
--font-tbh11-sans: 'Space Grotesk', ui-monospace, sans-serif;
}
/* Nothing stays CSS: two shadow stacks, two translates, one colour flip. */
.tbh-11-group {
width: 100%;
min-height: 100svh;
}
.tbh-11a,
.tbh-11b {
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=Space+Grotesk:wght@500;600;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=Space+Grotesk:wght@500;600;700&display=swap">What changed in the port
Which parts became utilities, which stayed CSS, and why.
- A shared
--color-tbh11-inktoken is the quiet improvement: the border, the label, the shadow and the focus ring are all the same black by reference rather than four copies of#111, so the brutalist palette cannot drift. hover:translate-x-[7px] hover:translate-y-[7px]instead of onetranslate(7px,7px)reads as two facts, which is correct here — design B is negative on X and positive on Y, and the split makes that asymmetry obvious.- UI change from the CSS original: both designs now fire the snap and the colour/neon flip on
focus-visible:, and the reduced-motion fallback keeps the neon and the background flip while dropping only the travel — the original dropped the whole hover for those users.
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 Neo-Brutalist & Cyberpunk Button Glow Effects
Source: https://codefronts.com/motion/tailwind-css-button-hover-effects/tailwind-neo-brutalist-cyberpunk-button-glow-effects/
A loud neo-brutalist CTA: flat fill, thick solid border and a hard blur-free offset shadow. On hover it snaps onto its shadow and the shadow flips to saturated neon — a hard, instant snap, not a soft glow. The port makes the effect's one invariant visible: the snap distance and the shadow offset are the same number.
## HTML
```html
<div class="tbh-11-group w-full min-h-svh flex flex-wrap">
<section class="tbh-11a flex-[1_1_340px] min-w-[300px] grid place-items-center px-6 py-14 font-tbh11-sans bg-tbh11a-stage" aria-label="Neo-brutalist neon button">
<button type="button" class="cursor-pointer rounded-none border-[3px] border-tbh11-ink px-[38px] py-[17px] text-[17px] font-extrabold uppercase tracking-[0.02em] text-tbh11-ink bg-white shadow-[7px_7px_0_var(--color-tbh11-ink)] transition-[translate,scale,box-shadow] duration-[120ms] ease-out hover:translate-x-[7px] hover:translate-y-[7px] hover:shadow-[0_0_0_var(--color-tbh11-ink),0_0_22px_2px_var(--color-tbh11a-mag),0_0_34px_6px_color-mix(in_oklab,var(--color-tbh11a-cyan)_70%,transparent)] focus-visible:translate-x-[7px] focus-visible:translate-y-[7px] focus-visible:shadow-[0_0_0_var(--color-tbh11-ink),0_0_22px_2px_var(--color-tbh11a-mag)] active:scale-[.98] focus-visible:outline-3 focus-visible:outline-tbh11-ink focus-visible:outline-offset-[5px] motion-reduce:transition-[box-shadow] motion-reduce:hover:translate-x-0 motion-reduce:hover:translate-y-0">
Subscribe
</button>
</section>
<section class="tbh-11b flex-[1_1_340px] min-w-[300px] grid place-items-center px-6 py-14 font-tbh11-sans bg-tbh11b-stage" aria-label="Brutalist sticker button">
<button type="button" class="cursor-pointer rounded-[10px] border-[3px] border-tbh11-ink px-10 py-[17px] text-[17px] font-extrabold uppercase text-tbh11-ink bg-tbh11b-lime shadow-[-6px_6px_0_var(--color-tbh11-ink)] transition-[translate,scale,box-shadow,background-color] duration-[120ms] ease-out hover:-translate-x-[6px] hover:translate-y-[6px] hover:bg-tbh11b-hot hover:shadow-[0_0_0_var(--color-tbh11-ink)] focus-visible:-translate-x-[6px] focus-visible:translate-y-[6px] focus-visible:bg-tbh11b-hot focus-visible:shadow-[0_0_0_var(--color-tbh11-ink)] active:scale-[.98] focus-visible:outline-3 focus-visible:outline-white focus-visible:outline-offset-[5px] motion-reduce:transition-[background-color,box-shadow] motion-reduce:hover:translate-x-0 motion-reduce:hover:translate-y-0">
Get access
</button>
</section>
</div>
```
## CSS
```css
@import "tailwindcss";
@theme {
--color-tbh11-ink: #111111;
--color-tbh11-ink: oklch(0.15 0 0);
--color-tbh11a-stage: #f5e94a;
--color-tbh11a-stage: oklch(0.92 0.18 100);
--color-tbh11a-mag: #ff2bd6;
--color-tbh11a-mag: oklch(0.7 0.28 330);
--color-tbh11a-cyan: #22e3ff;
--color-tbh11a-cyan: oklch(0.85 0.15 210);
--color-tbh11b-stage: #111111;
--color-tbh11b-stage: oklch(0.15 0 0);
--color-tbh11b-lime: #4df08a;
--color-tbh11b-lime: oklch(0.85 0.2 150);
--color-tbh11b-hot: #ffe14d;
--color-tbh11b-hot: oklch(0.91 0.17 95);
--font-tbh11-sans: 'Space Grotesk', ui-monospace, sans-serif;
}
/* Nothing stays CSS: two shadow stacks, two translates, one colour flip. */
.tbh-11-group {
width: 100%;
min-height: 100svh;
}
.tbh-11a,
.tbh-11b {
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 Neo-Brutalist & Cyberpunk Button Glow Effects
Source: https://codefronts.com/motion/tailwind-css-button-hover-effects/tailwind-neo-brutalist-cyberpunk-button-glow-effects/
A loud neo-brutalist CTA: flat fill, thick solid border and a hard blur-free offset shadow. On hover it snaps onto its shadow and the shadow flips to saturated neon — a hard, instant snap, not a soft glow. The port makes the effect's one invariant visible: the snap distance and the shadow offset are the same number.
## HTML
```html
<div class="tbh-11-group w-full min-h-svh flex flex-wrap">
<section class="tbh-11a flex-[1_1_340px] min-w-[300px] grid place-items-center px-6 py-14 font-tbh11-sans bg-tbh11a-stage" aria-label="Neo-brutalist neon button">
<button type="button" class="cursor-pointer rounded-none border-[3px] border-tbh11-ink px-[38px] py-[17px] text-[17px] font-extrabold uppercase tracking-[0.02em] text-tbh11-ink bg-white shadow-[7px_7px_0_var(--color-tbh11-ink)] transition-[translate,scale,box-shadow] duration-[120ms] ease-out hover:translate-x-[7px] hover:translate-y-[7px] hover:shadow-[0_0_0_var(--color-tbh11-ink),0_0_22px_2px_var(--color-tbh11a-mag),0_0_34px_6px_color-mix(in_oklab,var(--color-tbh11a-cyan)_70%,transparent)] focus-visible:translate-x-[7px] focus-visible:translate-y-[7px] focus-visible:shadow-[0_0_0_var(--color-tbh11-ink),0_0_22px_2px_var(--color-tbh11a-mag)] active:scale-[.98] focus-visible:outline-3 focus-visible:outline-tbh11-ink focus-visible:outline-offset-[5px] motion-reduce:transition-[box-shadow] motion-reduce:hover:translate-x-0 motion-reduce:hover:translate-y-0">
Subscribe
</button>
</section>
<section class="tbh-11b flex-[1_1_340px] min-w-[300px] grid place-items-center px-6 py-14 font-tbh11-sans bg-tbh11b-stage" aria-label="Brutalist sticker button">
<button type="button" class="cursor-pointer rounded-[10px] border-[3px] border-tbh11-ink px-10 py-[17px] text-[17px] font-extrabold uppercase text-tbh11-ink bg-tbh11b-lime shadow-[-6px_6px_0_var(--color-tbh11-ink)] transition-[translate,scale,box-shadow,background-color] duration-[120ms] ease-out hover:-translate-x-[6px] hover:translate-y-[6px] hover:bg-tbh11b-hot hover:shadow-[0_0_0_var(--color-tbh11-ink)] focus-visible:-translate-x-[6px] focus-visible:translate-y-[6px] focus-visible:bg-tbh11b-hot focus-visible:shadow-[0_0_0_var(--color-tbh11-ink)] active:scale-[.98] focus-visible:outline-3 focus-visible:outline-white focus-visible:outline-offset-[5px] motion-reduce:transition-[background-color,box-shadow] motion-reduce:hover:translate-x-0 motion-reduce:hover:translate-y-0">
Get access
</button>
</section>
</div>
```
## CSS
```css
@import "tailwindcss";
@theme {
--color-tbh11-ink: #111111;
--color-tbh11-ink: oklch(0.15 0 0);
--color-tbh11a-stage: #f5e94a;
--color-tbh11a-stage: oklch(0.92 0.18 100);
--color-tbh11a-mag: #ff2bd6;
--color-tbh11a-mag: oklch(0.7 0.28 330);
--color-tbh11a-cyan: #22e3ff;
--color-tbh11a-cyan: oklch(0.85 0.15 210);
--color-tbh11b-stage: #111111;
--color-tbh11b-stage: oklch(0.15 0 0);
--color-tbh11b-lime: #4df08a;
--color-tbh11b-lime: oklch(0.85 0.2 150);
--color-tbh11b-hot: #ffe14d;
--color-tbh11b-hot: oklch(0.91 0.17 95);
--font-tbh11-sans: 'Space Grotesk', ui-monospace, sans-serif;
}
/* Nothing stays CSS: two shadow stacks, two translates, one colour flip. */
.tbh-11-group {
width: 100%;
min-height: 100svh;
}
.tbh-11a,
.tbh-11b {
min-height: 100svh;
}
```How this works
The snap is arithmetic you can now see. The button floats 7px up-left of its shadow; hover translates it exactly 7px down-right while the shadow collapses to 0_0_0. If those numbers disagree the button appears to slide rather than land, and in the CSS version they lived in two different rules. Here they are adjacent.
No blur, no radius, on purpose. rounded-none is a deliberate utility, not an omission — the soft-glow treatment is a different demo, and stating the sharpness explicitly keeps someone from 'fixing' it later.
Design B swaps neon for a colour flip. Same mechanics mirrored to the left (-6px 6px), plus hover:bg-tbh11b-hot, which is the sticker-print version of the same joke.
Make it yours
- Neon pair:
--color-tbh11a-magand-cyan; the two glow layers read them. - Snap distance: the resting
shadow-[7px_7px_0_...]and thehover:translate-*-[7px]pair, changed together. - Monochrome brutalist: drop the two glow layers from the hover shadow and keep
0_0_0— the snap alone still reads. - Border weight:
border-[3px]. Below 2px the style stops being brutalist.
Gotchas — read before shipping
- The hover translate MUST equal the resting shadow offset, on both axes and including the sign — design B is negative on X.
- Keep the transition at ~120ms. The whole point is a mechanical snap; 300ms turns it into a glide.
- Blur-free is intentional. A soft glow at rest is a different aesthetic (and a different demo), and mixing them muddies both.
focus-visible:outline-offset-5clears the 3px border and the shadow, so the ring reads as a ring rather than a second border.
Browser support
| Chrome | Safari | Firefox | Edge |
|---|---|---|---|
| 111+ | 16.4+ | 128+ | 111+ |
Solid box-shadow and transforms are universal; nothing here needs a fallback beyond Tailwind v4's own floor.