09 / 30
All 30 in 30 Tailwind CSS Text Hover Effects
- 01Tailwind CSS Animated Underline Hover Effect
- 02Tailwind Liquid Text Fill Hover Animation
- 03Tailwind Gradient Text Hover Effect with bg-clip-text
- 04Tailwind Animated Strikethrough Text Hover Effect
- 05Tailwind Text Swap and Flip Up Hover Effect
- 06Tailwind CSS Glitch Text Hover Effect
- 07Tailwind Neon Glow Text with Flicker Animation
- 08Tailwind Metallic Gold Shimmer Text Effect
- 09Tailwind 3D Text Pop and Lift Hover Effect
- 10Tailwind Staggered Letter Wave Hover Animation
- 11Tailwind Spotlight Text Reveal on Mouse Hover
- 12Tailwind Hover to Reveal Hidden Spoiler Text
- 13Tailwind Blur to Focus Text Hover Effect
- 14Tailwind Magnetic Hover Effect for Buttons and Text
- 15Tailwind Letter Spacing Expand on Hover (Tracking Animation)
- 16Tailwind Outline Text Stroke to Fill Hover Effect
- 17Tailwind Text Scramble and Matrix Decrypt Hover Effect
- 18Tailwind Animated Border Button Hover Effect
- 19Tailwind Elastic Rubber Band Text Hover Animation
- 20Tailwind Variable Font Weight Hover Animation
- 21Tailwind Animated Rainbow Gradient Text on Hover
- 22Tailwind 3D Perspective Tilt Text Hover Effect
- 23Tailwind Smoke Dissolve Text Hover Effect
- 24Tailwind Fire Text Effect with Heat Wave Glow
- 25Tailwind Dynamic Text Shadow that Follows the Cursor
- 26Tailwind Infinite Text Marquee that Speeds Up on Hover
- 27Tailwind Duotone Split Color Text Hover Effect
- 28Tailwind CSS Tooltip on Hover (No JavaScript)
- 29Tailwind SVG Water Ripple Distortion Text Effect
- 30Tailwind Clip-Path Text Reveal Hover Animation
Tailwind 3D Text Pop and Lift Hover Effect
A festival headline that pops out of the page: six same-length text-shadow layers interpolate from 0 to an extruded side, with active: pressing it back in on click. Matching neo-brutalist buttons lift and press with box-shadow. Everything rides a springy cubic-bezier(.34,1.8,.4,1).
Untitled UI Pro: 5,000+ React + Tailwind CSS v4 components · from $349 one-time
Untitled UI React · Affiliate link
The code
<section class="tth-09 w-full min-h-svh grid place-items-center bg-tth09-bg bg-[radial-gradient(90%_70%_at_50%_20%,var(--color-tth09-glow),var(--color-tth09-bg)_75%)] px-5 py-14 font-tth09-sans text-tth09-ink" aria-label="3D pop lift text demo">
<div class="flex flex-col items-center gap-[clamp(16px,3vw,24px)] text-center">
<p class="text-[12.5px] font-extrabold uppercase tracking-[0.24em] text-tth09-mut">Riverside park · Jan 30–31 · all ages</p>
<h2 class="leading-[0.96]"><a id="tth09-top" href="#tth09-top" class="inline-block rounded-md text-[clamp(58px,13vw,132px)] font-black tracking-[-0.015em] no-underline [text-shadow:0_0_0_var(--color-tth09-side),0_0_0_var(--color-tth09-side),0_0_0_var(--color-tth09-side),0_0_0_var(--color-tth09-side),0_0_0_var(--color-tth09-side),0_0_0_var(--color-tth09-side),0_0_0_transparent] transition-[translate,text-shadow] duration-300 ease-[cubic-bezier(.34,1.8,.4,1)] hover:translate-x-[0.05em] hover:-translate-y-[0.14em] hover:[text-shadow:.02em_.02em_0_var(--color-tth09-side),.045em_.045em_0_var(--color-tth09-side),.07em_.07em_0_var(--color-tth09-side),.095em_.095em_0_var(--color-tth09-side),.12em_.12em_0_var(--color-tth09-side),.145em_.145em_0_var(--color-tth09-side),.3em_.42em_1em_oklch(0.3_0.08_300/.35)] focus-visible:translate-x-[0.05em] focus-visible:-translate-y-[0.14em] focus-visible:[text-shadow:.02em_.02em_0_var(--color-tth09-side),.045em_.045em_0_var(--color-tth09-side),.07em_.07em_0_var(--color-tth09-side),.095em_.095em_0_var(--color-tth09-side),.12em_.12em_0_var(--color-tth09-side),.145em_.145em_0_var(--color-tth09-side),.3em_.42em_1em_oklch(0.3_0.08_300/.35)] focus-visible:outline-3 focus-visible:outline-offset-[10px] focus-visible:outline-tth09-side active:translate-x-[0.01em] active:translate-y-[0.02em] active:duration-90 active:[text-shadow:.008em_.008em_0_var(--color-tth09-side),.016em_.016em_0_var(--color-tth09-side),.024em_.024em_0_var(--color-tth09-side),.03em_.03em_0_var(--color-tth09-side),.036em_.036em_0_var(--color-tth09-side),.042em_.042em_0_var(--color-tth09-side),.05em_.08em_.2em_oklch(0.3_0.08_300/.3)] motion-reduce:transition-none">JELLY<br>JAM ’26</a></h2>
<p class="max-w-[44ch] text-[15px] font-medium leading-[1.65] text-tth09-mut">Two days of wobble-pop, jam stalls and the inflatable orchestra. Hover the headline — then actually press it.</p>
<div class="mt-1 flex flex-wrap justify-center gap-3.5">
<a href="#tth09-top" class="grid min-h-[52px] place-items-center rounded-[14px] border-[2.5px] border-tth09-ink bg-tth09-side px-[26px] text-[15.5px] font-extrabold text-tth09-paper no-underline shadow-[0_0_0_0_var(--color-tth09-ink),0_0_0_0_transparent] transition-[translate,box-shadow] duration-220 ease-[cubic-bezier(.34,1.8,.4,1)] hover:-translate-x-0.5 hover:-translate-y-[5px] hover:shadow-[4px_6px_0_0_var(--color-tth09-ink),10px_16px_26px_-6px_oklch(0.3_0.08_300/0.3)] focus-visible:-translate-y-[5px] focus-visible:shadow-[4px_6px_0_0_var(--color-tth09-ink)] focus-visible:outline-3 focus-visible:outline-offset-[3px] focus-visible:outline-tth09-side active:translate-x-px active:translate-y-0.5 active:shadow-[0_0_0_0_var(--color-tth09-ink),0_0_0_0_transparent] active:duration-80 motion-reduce:transition-none">Get tickets</a>
<a href="#tth09-top" class="grid min-h-[52px] place-items-center rounded-[14px] border-[2.5px] border-tth09-ink bg-tth09-paper px-[26px] text-[15.5px] font-extrabold no-underline shadow-[0_0_0_0_var(--color-tth09-ink),0_0_0_0_transparent] transition-[translate,box-shadow] duration-220 ease-[cubic-bezier(.34,1.8,.4,1)] hover:-translate-x-0.5 hover:-translate-y-[5px] hover:shadow-[4px_6px_0_0_var(--color-tth09-ink),10px_16px_26px_-6px_oklch(0.3_0.08_300/0.3)] focus-visible:-translate-y-[5px] focus-visible:shadow-[4px_6px_0_0_var(--color-tth09-ink)] focus-visible:outline-3 focus-visible:outline-offset-[3px] focus-visible:outline-tth09-side active:translate-x-px active:translate-y-0.5 active:shadow-[0_0_0_0_var(--color-tth09-ink),0_0_0_0_transparent] active:duration-80 motion-reduce:transition-none">Line-up</a>
</div>
<p class="text-[12.5px] text-tth09-mut">Same-length <code class="rounded bg-tth09-chip px-1.5 py-px font-tth09-mono text-[0.9em]">text-shadow</code> lists interpolate — the extrusion grows, never blinks. <code class="rounded bg-tth09-chip px-1.5 py-px font-tth09-mono text-[0.9em]">active:</code> presses it back into the page.</p>
</div>
</section><section class="tth-09 w-full min-h-svh grid place-items-center bg-tth09-bg bg-[radial-gradient(90%_70%_at_50%_20%,var(--color-tth09-glow),var(--color-tth09-bg)_75%)] px-5 py-14 font-tth09-sans text-tth09-ink" aria-label="3D pop lift text demo">
<div class="flex flex-col items-center gap-[clamp(16px,3vw,24px)] text-center">
<p class="text-[12.5px] font-extrabold uppercase tracking-[0.24em] text-tth09-mut">Riverside park · Jan 30–31 · all ages</p>
<h2 class="leading-[0.96]"><a id="tth09-top" href="#tth09-top" class="inline-block rounded-md text-[clamp(58px,13vw,132px)] font-black tracking-[-0.015em] no-underline [text-shadow:0_0_0_var(--color-tth09-side),0_0_0_var(--color-tth09-side),0_0_0_var(--color-tth09-side),0_0_0_var(--color-tth09-side),0_0_0_var(--color-tth09-side),0_0_0_var(--color-tth09-side),0_0_0_transparent] transition-[translate,text-shadow] duration-300 ease-[cubic-bezier(.34,1.8,.4,1)] hover:translate-x-[0.05em] hover:-translate-y-[0.14em] hover:[text-shadow:.02em_.02em_0_var(--color-tth09-side),.045em_.045em_0_var(--color-tth09-side),.07em_.07em_0_var(--color-tth09-side),.095em_.095em_0_var(--color-tth09-side),.12em_.12em_0_var(--color-tth09-side),.145em_.145em_0_var(--color-tth09-side),.3em_.42em_1em_oklch(0.3_0.08_300/.35)] focus-visible:translate-x-[0.05em] focus-visible:-translate-y-[0.14em] focus-visible:[text-shadow:.02em_.02em_0_var(--color-tth09-side),.045em_.045em_0_var(--color-tth09-side),.07em_.07em_0_var(--color-tth09-side),.095em_.095em_0_var(--color-tth09-side),.12em_.12em_0_var(--color-tth09-side),.145em_.145em_0_var(--color-tth09-side),.3em_.42em_1em_oklch(0.3_0.08_300/.35)] focus-visible:outline-3 focus-visible:outline-offset-[10px] focus-visible:outline-tth09-side active:translate-x-[0.01em] active:translate-y-[0.02em] active:duration-90 active:[text-shadow:.008em_.008em_0_var(--color-tth09-side),.016em_.016em_0_var(--color-tth09-side),.024em_.024em_0_var(--color-tth09-side),.03em_.03em_0_var(--color-tth09-side),.036em_.036em_0_var(--color-tth09-side),.042em_.042em_0_var(--color-tth09-side),.05em_.08em_.2em_oklch(0.3_0.08_300/.3)] motion-reduce:transition-none">JELLY<br>JAM ’26</a></h2>
<p class="max-w-[44ch] text-[15px] font-medium leading-[1.65] text-tth09-mut">Two days of wobble-pop, jam stalls and the inflatable orchestra. Hover the headline — then actually press it.</p>
<div class="mt-1 flex flex-wrap justify-center gap-3.5">
<a href="#tth09-top" class="grid min-h-[52px] place-items-center rounded-[14px] border-[2.5px] border-tth09-ink bg-tth09-side px-[26px] text-[15.5px] font-extrabold text-tth09-paper no-underline shadow-[0_0_0_0_var(--color-tth09-ink),0_0_0_0_transparent] transition-[translate,box-shadow] duration-220 ease-[cubic-bezier(.34,1.8,.4,1)] hover:-translate-x-0.5 hover:-translate-y-[5px] hover:shadow-[4px_6px_0_0_var(--color-tth09-ink),10px_16px_26px_-6px_oklch(0.3_0.08_300/0.3)] focus-visible:-translate-y-[5px] focus-visible:shadow-[4px_6px_0_0_var(--color-tth09-ink)] focus-visible:outline-3 focus-visible:outline-offset-[3px] focus-visible:outline-tth09-side active:translate-x-px active:translate-y-0.5 active:shadow-[0_0_0_0_var(--color-tth09-ink),0_0_0_0_transparent] active:duration-80 motion-reduce:transition-none">Get tickets</a>
<a href="#tth09-top" class="grid min-h-[52px] place-items-center rounded-[14px] border-[2.5px] border-tth09-ink bg-tth09-paper px-[26px] text-[15.5px] font-extrabold no-underline shadow-[0_0_0_0_var(--color-tth09-ink),0_0_0_0_transparent] transition-[translate,box-shadow] duration-220 ease-[cubic-bezier(.34,1.8,.4,1)] hover:-translate-x-0.5 hover:-translate-y-[5px] hover:shadow-[4px_6px_0_0_var(--color-tth09-ink),10px_16px_26px_-6px_oklch(0.3_0.08_300/0.3)] focus-visible:-translate-y-[5px] focus-visible:shadow-[4px_6px_0_0_var(--color-tth09-ink)] focus-visible:outline-3 focus-visible:outline-offset-[3px] focus-visible:outline-tth09-side active:translate-x-px active:translate-y-0.5 active:shadow-[0_0_0_0_var(--color-tth09-ink),0_0_0_0_transparent] active:duration-80 motion-reduce:transition-none">Line-up</a>
</div>
<p class="text-[12.5px] text-tth09-mut">Same-length <code class="rounded bg-tth09-chip px-1.5 py-px font-tth09-mono text-[0.9em]">text-shadow</code> lists interpolate — the extrusion grows, never blinks. <code class="rounded bg-tth09-chip px-1.5 py-px font-tth09-mono text-[0.9em]">active:</code> presses it back into the page.</p>
</div>
</section>@import "tailwindcss";
@theme {
--color-tth09-bg: #f6efd9;
--color-tth09-bg: oklch(0.95 0.035 95);
--color-tth09-glow: #fbf6e6;
--color-tth09-glow: oklch(0.975 0.025 95);
--color-tth09-paper: #fbf9f1;
--color-tth09-paper: oklch(0.98 0.01 95);
--color-tth09-chip: #eae1c6;
--color-tth09-chip: oklch(0.9 0.035 95);
--color-tth09-ink: #3d1c55;
--color-tth09-ink: oklch(0.3 0.09 305);
--color-tth09-mut: #5f4c69;
--color-tth09-mut: oklch(0.45 0.05 300);
--color-tth09-side: #ee6545;
--color-tth09-side: oklch(0.68 0.19 30);
--font-tth09-sans: 'Rubik', system-ui, sans-serif;
--font-tth09-mono: 'JetBrains Mono', ui-monospace, monospace;
}
.tth-09 {
width: 100%;
min-height: 100svh;
}@import "tailwindcss";
@theme {
--color-tth09-bg: #f6efd9;
--color-tth09-bg: oklch(0.95 0.035 95);
--color-tth09-glow: #fbf6e6;
--color-tth09-glow: oklch(0.975 0.025 95);
--color-tth09-paper: #fbf9f1;
--color-tth09-paper: oklch(0.98 0.01 95);
--color-tth09-chip: #eae1c6;
--color-tth09-chip: oklch(0.9 0.035 95);
--color-tth09-ink: #3d1c55;
--color-tth09-ink: oklch(0.3 0.09 305);
--color-tth09-mut: #5f4c69;
--color-tth09-mut: oklch(0.45 0.05 300);
--color-tth09-side: #ee6545;
--color-tth09-side: oklch(0.68 0.19 30);
--font-tth09-sans: 'Rubik', system-ui, sans-serif;
--font-tth09-mono: 'JetBrains Mono', ui-monospace, monospace;
}
.tth-09 {
width: 100%;
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-tth09-bg: #f6efd9;
--color-tth09-bg: oklch(0.95 0.035 95);
--color-tth09-glow: #fbf6e6;
--color-tth09-glow: oklch(0.975 0.025 95);
--color-tth09-paper: #fbf9f1;
--color-tth09-paper: oklch(0.98 0.01 95);
--color-tth09-chip: #eae1c6;
--color-tth09-chip: oklch(0.9 0.035 95);
--color-tth09-ink: #3d1c55;
--color-tth09-ink: oklch(0.3 0.09 305);
--color-tth09-mut: #5f4c69;
--color-tth09-mut: oklch(0.45 0.05 300);
--color-tth09-side: #ee6545;
--color-tth09-side: oklch(0.68 0.19 30);
--font-tth09-sans: 'Rubik', system-ui, sans-serif;
--font-tth09-mono: 'JetBrains Mono', ui-monospace, monospace;
}
.tth-09 {
width: 100%;
min-height: 100svh;
}@import "tailwindcss";
@theme {
--color-tth09-bg: #f6efd9;
--color-tth09-bg: oklch(0.95 0.035 95);
--color-tth09-glow: #fbf6e6;
--color-tth09-glow: oklch(0.975 0.025 95);
--color-tth09-paper: #fbf9f1;
--color-tth09-paper: oklch(0.98 0.01 95);
--color-tth09-chip: #eae1c6;
--color-tth09-chip: oklch(0.9 0.035 95);
--color-tth09-ink: #3d1c55;
--color-tth09-ink: oklch(0.3 0.09 305);
--color-tth09-mut: #5f4c69;
--color-tth09-mut: oklch(0.45 0.05 300);
--color-tth09-side: #ee6545;
--color-tth09-side: oklch(0.68 0.19 30);
--font-tth09-sans: 'Rubik', system-ui, sans-serif;
--font-tth09-mono: 'JetBrains Mono', ui-monospace, monospace;
}
.tth-09 {
width: 100%;
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=Rubik:wght@500..900&family=JetBrains+Mono:wght@400;600&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=Rubik:wght@500..900&family=JetBrains+Mono:wght@400;600&display=swap">What changed in the port
Which parts became utilities, which stayed CSS, and why.
- Rest, hover and
:activeshadow lists became three arbitrary[text-shadow:…]values on the link; the 90ms press isactive:duration-90— a state-scoped duration with no extra rule. - UI upgrade from the CSS original: Rubik Black's rounded corners make the extrusion read like a moulded jelly sweet instead of a hard Segoe block, and the buttons gained a coloured lift shadow that matches the headline.
- UI upgrade: muted copy darkened to
0.45L (6.6:1 on the cream stage; was 5.1:1).
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 3D Text Pop and Lift Hover Effect
Source: https://codefronts.com/motion/tailwind-css-text-hover-effects/tailwind-3d-text-pop-and-lift-hover-effect/
A festival headline that pops out of the page: six same-length text-shadow layers interpolate from 0 to an extruded side, with active: pressing it back in on click. Matching neo-brutalist buttons lift and press with box-shadow. Everything rides a springy cubic-bezier(.34,1.8,.4,1).
## HTML
```html
<section class="tth-09 w-full min-h-svh grid place-items-center bg-tth09-bg bg-[radial-gradient(90%_70%_at_50%_20%,var(--color-tth09-glow),var(--color-tth09-bg)_75%)] px-5 py-14 font-tth09-sans text-tth09-ink" aria-label="3D pop lift text demo">
<div class="flex flex-col items-center gap-[clamp(16px,3vw,24px)] text-center">
<p class="text-[12.5px] font-extrabold uppercase tracking-[0.24em] text-tth09-mut">Riverside park · Jan 30–31 · all ages</p>
<h2 class="leading-[0.96]"><a id="tth09-top" href="#tth09-top" class="inline-block rounded-md text-[clamp(58px,13vw,132px)] font-black tracking-[-0.015em] no-underline [text-shadow:0_0_0_var(--color-tth09-side),0_0_0_var(--color-tth09-side),0_0_0_var(--color-tth09-side),0_0_0_var(--color-tth09-side),0_0_0_var(--color-tth09-side),0_0_0_var(--color-tth09-side),0_0_0_transparent] transition-[translate,text-shadow] duration-300 ease-[cubic-bezier(.34,1.8,.4,1)] hover:translate-x-[0.05em] hover:-translate-y-[0.14em] hover:[text-shadow:.02em_.02em_0_var(--color-tth09-side),.045em_.045em_0_var(--color-tth09-side),.07em_.07em_0_var(--color-tth09-side),.095em_.095em_0_var(--color-tth09-side),.12em_.12em_0_var(--color-tth09-side),.145em_.145em_0_var(--color-tth09-side),.3em_.42em_1em_oklch(0.3_0.08_300/.35)] focus-visible:translate-x-[0.05em] focus-visible:-translate-y-[0.14em] focus-visible:[text-shadow:.02em_.02em_0_var(--color-tth09-side),.045em_.045em_0_var(--color-tth09-side),.07em_.07em_0_var(--color-tth09-side),.095em_.095em_0_var(--color-tth09-side),.12em_.12em_0_var(--color-tth09-side),.145em_.145em_0_var(--color-tth09-side),.3em_.42em_1em_oklch(0.3_0.08_300/.35)] focus-visible:outline-3 focus-visible:outline-offset-[10px] focus-visible:outline-tth09-side active:translate-x-[0.01em] active:translate-y-[0.02em] active:duration-90 active:[text-shadow:.008em_.008em_0_var(--color-tth09-side),.016em_.016em_0_var(--color-tth09-side),.024em_.024em_0_var(--color-tth09-side),.03em_.03em_0_var(--color-tth09-side),.036em_.036em_0_var(--color-tth09-side),.042em_.042em_0_var(--color-tth09-side),.05em_.08em_.2em_oklch(0.3_0.08_300/.3)] motion-reduce:transition-none">JELLY<br>JAM ’26</a></h2>
<p class="max-w-[44ch] text-[15px] font-medium leading-[1.65] text-tth09-mut">Two days of wobble-pop, jam stalls and the inflatable orchestra. Hover the headline — then actually press it.</p>
<div class="mt-1 flex flex-wrap justify-center gap-3.5">
<a href="#tth09-top" class="grid min-h-[52px] place-items-center rounded-[14px] border-[2.5px] border-tth09-ink bg-tth09-side px-[26px] text-[15.5px] font-extrabold text-tth09-paper no-underline shadow-[0_0_0_0_var(--color-tth09-ink),0_0_0_0_transparent] transition-[translate,box-shadow] duration-220 ease-[cubic-bezier(.34,1.8,.4,1)] hover:-translate-x-0.5 hover:-translate-y-[5px] hover:shadow-[4px_6px_0_0_var(--color-tth09-ink),10px_16px_26px_-6px_oklch(0.3_0.08_300/0.3)] focus-visible:-translate-y-[5px] focus-visible:shadow-[4px_6px_0_0_var(--color-tth09-ink)] focus-visible:outline-3 focus-visible:outline-offset-[3px] focus-visible:outline-tth09-side active:translate-x-px active:translate-y-0.5 active:shadow-[0_0_0_0_var(--color-tth09-ink),0_0_0_0_transparent] active:duration-80 motion-reduce:transition-none">Get tickets</a>
<a href="#tth09-top" class="grid min-h-[52px] place-items-center rounded-[14px] border-[2.5px] border-tth09-ink bg-tth09-paper px-[26px] text-[15.5px] font-extrabold no-underline shadow-[0_0_0_0_var(--color-tth09-ink),0_0_0_0_transparent] transition-[translate,box-shadow] duration-220 ease-[cubic-bezier(.34,1.8,.4,1)] hover:-translate-x-0.5 hover:-translate-y-[5px] hover:shadow-[4px_6px_0_0_var(--color-tth09-ink),10px_16px_26px_-6px_oklch(0.3_0.08_300/0.3)] focus-visible:-translate-y-[5px] focus-visible:shadow-[4px_6px_0_0_var(--color-tth09-ink)] focus-visible:outline-3 focus-visible:outline-offset-[3px] focus-visible:outline-tth09-side active:translate-x-px active:translate-y-0.5 active:shadow-[0_0_0_0_var(--color-tth09-ink),0_0_0_0_transparent] active:duration-80 motion-reduce:transition-none">Line-up</a>
</div>
<p class="text-[12.5px] text-tth09-mut">Same-length <code class="rounded bg-tth09-chip px-1.5 py-px font-tth09-mono text-[0.9em]">text-shadow</code> lists interpolate — the extrusion grows, never blinks. <code class="rounded bg-tth09-chip px-1.5 py-px font-tth09-mono text-[0.9em]">active:</code> presses it back into the page.</p>
</div>
</section>
```
## CSS
```css
@import "tailwindcss";
@theme {
--color-tth09-bg: #f6efd9;
--color-tth09-bg: oklch(0.95 0.035 95);
--color-tth09-glow: #fbf6e6;
--color-tth09-glow: oklch(0.975 0.025 95);
--color-tth09-paper: #fbf9f1;
--color-tth09-paper: oklch(0.98 0.01 95);
--color-tth09-chip: #eae1c6;
--color-tth09-chip: oklch(0.9 0.035 95);
--color-tth09-ink: #3d1c55;
--color-tth09-ink: oklch(0.3 0.09 305);
--color-tth09-mut: #5f4c69;
--color-tth09-mut: oklch(0.45 0.05 300);
--color-tth09-side: #ee6545;
--color-tth09-side: oklch(0.68 0.19 30);
--font-tth09-sans: 'Rubik', system-ui, sans-serif;
--font-tth09-mono: 'JetBrains Mono', ui-monospace, monospace;
}
.tth-09 {
width: 100%;
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 3D Text Pop and Lift Hover Effect
Source: https://codefronts.com/motion/tailwind-css-text-hover-effects/tailwind-3d-text-pop-and-lift-hover-effect/
A festival headline that pops out of the page: six same-length text-shadow layers interpolate from 0 to an extruded side, with active: pressing it back in on click. Matching neo-brutalist buttons lift and press with box-shadow. Everything rides a springy cubic-bezier(.34,1.8,.4,1).
## HTML
```html
<section class="tth-09 w-full min-h-svh grid place-items-center bg-tth09-bg bg-[radial-gradient(90%_70%_at_50%_20%,var(--color-tth09-glow),var(--color-tth09-bg)_75%)] px-5 py-14 font-tth09-sans text-tth09-ink" aria-label="3D pop lift text demo">
<div class="flex flex-col items-center gap-[clamp(16px,3vw,24px)] text-center">
<p class="text-[12.5px] font-extrabold uppercase tracking-[0.24em] text-tth09-mut">Riverside park · Jan 30–31 · all ages</p>
<h2 class="leading-[0.96]"><a id="tth09-top" href="#tth09-top" class="inline-block rounded-md text-[clamp(58px,13vw,132px)] font-black tracking-[-0.015em] no-underline [text-shadow:0_0_0_var(--color-tth09-side),0_0_0_var(--color-tth09-side),0_0_0_var(--color-tth09-side),0_0_0_var(--color-tth09-side),0_0_0_var(--color-tth09-side),0_0_0_var(--color-tth09-side),0_0_0_transparent] transition-[translate,text-shadow] duration-300 ease-[cubic-bezier(.34,1.8,.4,1)] hover:translate-x-[0.05em] hover:-translate-y-[0.14em] hover:[text-shadow:.02em_.02em_0_var(--color-tth09-side),.045em_.045em_0_var(--color-tth09-side),.07em_.07em_0_var(--color-tth09-side),.095em_.095em_0_var(--color-tth09-side),.12em_.12em_0_var(--color-tth09-side),.145em_.145em_0_var(--color-tth09-side),.3em_.42em_1em_oklch(0.3_0.08_300/.35)] focus-visible:translate-x-[0.05em] focus-visible:-translate-y-[0.14em] focus-visible:[text-shadow:.02em_.02em_0_var(--color-tth09-side),.045em_.045em_0_var(--color-tth09-side),.07em_.07em_0_var(--color-tth09-side),.095em_.095em_0_var(--color-tth09-side),.12em_.12em_0_var(--color-tth09-side),.145em_.145em_0_var(--color-tth09-side),.3em_.42em_1em_oklch(0.3_0.08_300/.35)] focus-visible:outline-3 focus-visible:outline-offset-[10px] focus-visible:outline-tth09-side active:translate-x-[0.01em] active:translate-y-[0.02em] active:duration-90 active:[text-shadow:.008em_.008em_0_var(--color-tth09-side),.016em_.016em_0_var(--color-tth09-side),.024em_.024em_0_var(--color-tth09-side),.03em_.03em_0_var(--color-tth09-side),.036em_.036em_0_var(--color-tth09-side),.042em_.042em_0_var(--color-tth09-side),.05em_.08em_.2em_oklch(0.3_0.08_300/.3)] motion-reduce:transition-none">JELLY<br>JAM ’26</a></h2>
<p class="max-w-[44ch] text-[15px] font-medium leading-[1.65] text-tth09-mut">Two days of wobble-pop, jam stalls and the inflatable orchestra. Hover the headline — then actually press it.</p>
<div class="mt-1 flex flex-wrap justify-center gap-3.5">
<a href="#tth09-top" class="grid min-h-[52px] place-items-center rounded-[14px] border-[2.5px] border-tth09-ink bg-tth09-side px-[26px] text-[15.5px] font-extrabold text-tth09-paper no-underline shadow-[0_0_0_0_var(--color-tth09-ink),0_0_0_0_transparent] transition-[translate,box-shadow] duration-220 ease-[cubic-bezier(.34,1.8,.4,1)] hover:-translate-x-0.5 hover:-translate-y-[5px] hover:shadow-[4px_6px_0_0_var(--color-tth09-ink),10px_16px_26px_-6px_oklch(0.3_0.08_300/0.3)] focus-visible:-translate-y-[5px] focus-visible:shadow-[4px_6px_0_0_var(--color-tth09-ink)] focus-visible:outline-3 focus-visible:outline-offset-[3px] focus-visible:outline-tth09-side active:translate-x-px active:translate-y-0.5 active:shadow-[0_0_0_0_var(--color-tth09-ink),0_0_0_0_transparent] active:duration-80 motion-reduce:transition-none">Get tickets</a>
<a href="#tth09-top" class="grid min-h-[52px] place-items-center rounded-[14px] border-[2.5px] border-tth09-ink bg-tth09-paper px-[26px] text-[15.5px] font-extrabold no-underline shadow-[0_0_0_0_var(--color-tth09-ink),0_0_0_0_transparent] transition-[translate,box-shadow] duration-220 ease-[cubic-bezier(.34,1.8,.4,1)] hover:-translate-x-0.5 hover:-translate-y-[5px] hover:shadow-[4px_6px_0_0_var(--color-tth09-ink),10px_16px_26px_-6px_oklch(0.3_0.08_300/0.3)] focus-visible:-translate-y-[5px] focus-visible:shadow-[4px_6px_0_0_var(--color-tth09-ink)] focus-visible:outline-3 focus-visible:outline-offset-[3px] focus-visible:outline-tth09-side active:translate-x-px active:translate-y-0.5 active:shadow-[0_0_0_0_var(--color-tth09-ink),0_0_0_0_transparent] active:duration-80 motion-reduce:transition-none">Line-up</a>
</div>
<p class="text-[12.5px] text-tth09-mut">Same-length <code class="rounded bg-tth09-chip px-1.5 py-px font-tth09-mono text-[0.9em]">text-shadow</code> lists interpolate — the extrusion grows, never blinks. <code class="rounded bg-tth09-chip px-1.5 py-px font-tth09-mono text-[0.9em]">active:</code> presses it back into the page.</p>
</div>
</section>
```
## CSS
```css
@import "tailwindcss";
@theme {
--color-tth09-bg: #f6efd9;
--color-tth09-bg: oklch(0.95 0.035 95);
--color-tth09-glow: #fbf6e6;
--color-tth09-glow: oklch(0.975 0.025 95);
--color-tth09-paper: #fbf9f1;
--color-tth09-paper: oklch(0.98 0.01 95);
--color-tth09-chip: #eae1c6;
--color-tth09-chip: oklch(0.9 0.035 95);
--color-tth09-ink: #3d1c55;
--color-tth09-ink: oklch(0.3 0.09 305);
--color-tth09-mut: #5f4c69;
--color-tth09-mut: oklch(0.45 0.05 300);
--color-tth09-side: #ee6545;
--color-tth09-side: oklch(0.68 0.19 30);
--font-tth09-sans: 'Rubik', system-ui, sans-serif;
--font-tth09-mono: 'JetBrains Mono', ui-monospace, monospace;
}
.tth-09 {
width: 100%;
min-height: 100svh;
}
```How this works
Same length, or it blinks. Shadow lists only interpolate when both states have the same number of layers. So the rest state declares six collapsed layers 0 0 0 var(--color-tth09-side) plus a transparent seventh, and hover spreads them along a diagonal:
hover:[text-shadow:.02em_.02em_0_var(--color-tth09-side),
.045em_.045em_0_…, … ,.145em_.145em_0_…,
.3em_.42em_1em_oklch(0.3_0.08_300/.35)]Press. active: shrinks the extrusion to a sliver and shortens the duration to 90ms, so the press snaps while the release springs back over 300ms.
Make it yours
- Deeper extrusion: add layers (and matching zero layers at rest) in steps of .025em.
- Colour:
--color-tth09-sidesets the extruded face; try the ink colour for a monochrome block. - Direction: negate the x offsets to extrude down-left.
Gotchas — read before shipping
- Mismatched layer counts make the shadow jump instead of grow.
emoffsets keep the extrusion proportional at everyclamp()size.- Long text-shadow lists are hard to read in markup — move them to
--text-shadow-*tokens if you reuse them.
Browser support
| Chrome | Safari | Firefox | Edge |
|---|---|---|---|
| 111+ | 16.4+ | 128+ | 111+ |
Universal; the floor is Tailwind v4's sheet.