30 Tailwind CSS Text Hover Effects
22 / 30
Pure TailwindMIT licensed

Tailwind 3D Perspective Tilt Text Hover Effect

A conference wordmark that leans toward the cursor from any corner — without JavaScript. Four invisible quadrant zones are named peers (peer/tl…peer/br); the word reads peer-hover/tl:rotate-x-[11deg] peer-hover/tl:-rotate-y-[13deg] and a matching shadow that always falls away from the tilt. Keyboard focus plays a gentle sway.

Live Demo
Plain CSSTailwind v4
Try it

Untitled UI Pro: 5,000+ React + Tailwind CSS v4 components · from $349 one-time

Untitled UI React · Affiliate link

Get Untitled UI Pro

The code

<section class="tth-22 w-full min-h-svh grid place-items-center bg-tth22-bg bg-[radial-gradient(80%_65%_at_50%_30%,var(--color-tth22-glow),var(--color-tth22-bg)_75%)] px-5 py-14 font-tth22-sans text-tth22-ink" aria-label="Perspective tilt text demo">
  <div class="flex flex-col items-center gap-[clamp(18px,3.4vw,28px)] text-center">
    <p class="text-[12.5px] font-extrabold uppercase tracking-[0.24em] text-tth22-mut">Pivot &mdash; the design systems summit</p>
    <a id="tth22-top" href="#tth22-top" aria-label="PIVOT '26 — get tickets" class="group/tilt relative block rounded-2xl px-[clamp(20px,4vw,44px)] py-[clamp(16px,3vw,30px)] no-underline perspective-[850px] focus-visible:outline-[2.5px] focus-visible:outline-offset-4 focus-visible:outline-tth22-acc">
      <i aria-hidden="true" class="peer/tl absolute left-0 top-0 z-10 size-1/2"></i><i aria-hidden="true" class="peer/tr absolute right-0 top-0 z-10 size-1/2"></i><i aria-hidden="true" class="peer/bl absolute bottom-0 left-0 z-10 size-1/2"></i><i aria-hidden="true" class="peer/br absolute bottom-0 right-0 z-10 size-1/2"></i>
      <span aria-hidden="true" class="block text-[clamp(58px,13.5vw,140px)] font-black leading-none tracking-[-0.04em] [text-shadow:0_.06em_.09em_oklch(0.2_0.02_270/0.22)] transition-[transform,text-shadow] duration-500 ease-[cubic-bezier(.2,.8,.25,1)] peer-hover/tl:rotate-x-[11deg] peer-hover/tl:-rotate-y-[13deg] peer-hover/tl:[text-shadow:.07em_.11em_.13em_oklch(0.2_0.02_270/0.42)] peer-hover/tr:rotate-x-[11deg] peer-hover/tr:rotate-y-[13deg] peer-hover/tr:[text-shadow:-.07em_.11em_.13em_oklch(0.2_0.02_270/0.42)] peer-hover/bl:-rotate-x-[11deg] peer-hover/bl:-rotate-y-[13deg] peer-hover/bl:[text-shadow:.07em_-.07em_.13em_oklch(0.2_0.02_270/0.4)] peer-hover/br:-rotate-x-[11deg] peer-hover/br:rotate-y-[13deg] peer-hover/br:[text-shadow:-.07em_-.07em_.13em_oklch(0.2_0.02_270/0.4)] group-focus-visible/tilt:animate-tth22-sway motion-reduce:transition-none motion-reduce:animate-none!">PIVOT<span class="text-tth22-acc">&rsquo;26</span></span>
    </a>
    <p class="max-w-[52ch] text-[15px] leading-[1.7] text-tth22-mut">Approach the wordmark from any corner &mdash; it leans toward you. Four invisible hover quadrants, four poses, one transition blending them. No script.</p>
    <p class="text-[12.5px] text-tth22-mut">The shadow always slides opposite the tilt &mdash; fixed lamp, turning object. <kbd class="rounded-[5px] border border-b-2 border-tth22-line bg-white px-1.5 py-0.5 font-tth22-mono text-[11px]">Tab</kbd> to it for the keyboard sway.</p>
  </div>
</section>
@import "tailwindcss";

@theme {
  --color-tth22-bg: #eceef3;
  --color-tth22-bg: oklch(0.94 0.006 260);
  --color-tth22-glow: #f6f7fa;
  --color-tth22-glow: oklch(0.975 0.004 260);
  --color-tth22-ink: #1a1c2b;
  --color-tth22-ink: oklch(0.22 0.02 270);
  --color-tth22-mut: #5a5d6c;
  --color-tth22-mut: oklch(0.47 0.015 265);
  --color-tth22-acc: #3c55d8;
  --color-tth22-acc: oklch(0.52 0.2 265);
  --color-tth22-line: #d4d6de;
  --color-tth22-line: oklch(0.86 0.008 260);
  --font-tth22-sans: 'Schibsted Grotesk', system-ui, sans-serif;
  --font-tth22-mono: 'JetBrains Mono', ui-monospace, monospace;
  --animate-tth22-sway: tth22-sway 3.2s ease-in-out infinite;

  @keyframes tth22-sway {
    0%,
        100% {
      transform: rotateX(9deg) rotateY(-11deg);
    }

    50% {
      transform: rotateX(-9deg) rotateY(11deg);
    }
  }
}

.tth-22 {
  width: 100%;
  min-height: 100svh;
}

Setup — do this once per project

Skip this if your project already runs Tailwind v4.

1Load Tailwind
<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.

2Add the stylesheetRequiredthe @theme block is what makes the custom utilities exist
@import "tailwindcss";

@theme {
  --color-tth22-bg: #eceef3;
  --color-tth22-bg: oklch(0.94 0.006 260);
  --color-tth22-glow: #f6f7fa;
  --color-tth22-glow: oklch(0.975 0.004 260);
  --color-tth22-ink: #1a1c2b;
  --color-tth22-ink: oklch(0.22 0.02 270);
  --color-tth22-mut: #5a5d6c;
  --color-tth22-mut: oklch(0.47 0.015 265);
  --color-tth22-acc: #3c55d8;
  --color-tth22-acc: oklch(0.52 0.2 265);
  --color-tth22-line: #d4d6de;
  --color-tth22-line: oklch(0.86 0.008 260);
  --font-tth22-sans: 'Schibsted Grotesk', system-ui, sans-serif;
  --font-tth22-mono: 'JetBrains Mono', ui-monospace, monospace;
  --animate-tth22-sway: tth22-sway 3.2s ease-in-out infinite;

  @keyframes tth22-sway {
    0%,
        100% {
      transform: rotateX(9deg) rotateY(-11deg);
    }

    50% {
      transform: rotateX(-9deg) rotateY(11deg);
    }
  }
}

.tth-22 {
  width: 100%;
  min-height: 100svh;
}
3Fonts used by this demooptional — skip if you have your own type stack
<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=Schibsted+Grotesk:wght@400..900&family=JetBrains+Mono:wght@400;600&display=swap">

What changed in the port

Which parts became utilities, which stayed CSS, and why.

  • Four .z--tl:hover ~ .word sibling rules became named-peer variants (peer-hover/tl: … peer-hover/br:) on the word; v4's rotate-x-*/rotate-y-* replaced the hand-written transform chains.
  • UI upgrade from the CSS original: the wordmark was a tabindex="0" div — focusable but inert. It's now a real link (“PIVOT ’26 — get tickets”), so keyboard focus leads somewhere.
  • UI upgrade: the ’26 is set in the accent, Schibsted Grotesk Black gives tighter, sturdier letterforms, and muted copy rose to 6:1.
Paste this into ChatGPT, Claude, Cursor, or any coding assistant. The block below is pre-framed with everything the AI needs to integrate this demo into your project — markup, styles, scoping notes, and the source URL. Hit Copy and paste straight into your chat.
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 Perspective Tilt Text Hover Effect
Source: https://codefronts.com/motion/tailwind-css-text-hover-effects/tailwind-3d-perspective-tilt-text-hover-effect/

A conference wordmark that leans toward the cursor from any corner — without JavaScript. Four invisible quadrant zones are named peers (peer/tl…peer/br); the word reads peer-hover/tl:rotate-x-[11deg] peer-hover/tl:-rotate-y-[13deg] and a matching shadow that always falls away from the tilt. Keyboard focus plays a gentle sway.
## HTML
```html
<section class="tth-22 w-full min-h-svh grid place-items-center bg-tth22-bg bg-[radial-gradient(80%_65%_at_50%_30%,var(--color-tth22-glow),var(--color-tth22-bg)_75%)] px-5 py-14 font-tth22-sans text-tth22-ink" aria-label="Perspective tilt text demo">
  <div class="flex flex-col items-center gap-[clamp(18px,3.4vw,28px)] text-center">
    <p class="text-[12.5px] font-extrabold uppercase tracking-[0.24em] text-tth22-mut">Pivot &mdash; the design systems summit</p>
    <a id="tth22-top" href="#tth22-top" aria-label="PIVOT '26 — get tickets" class="group/tilt relative block rounded-2xl px-[clamp(20px,4vw,44px)] py-[clamp(16px,3vw,30px)] no-underline perspective-[850px] focus-visible:outline-[2.5px] focus-visible:outline-offset-4 focus-visible:outline-tth22-acc">
      <i aria-hidden="true" class="peer/tl absolute left-0 top-0 z-10 size-1/2"></i><i aria-hidden="true" class="peer/tr absolute right-0 top-0 z-10 size-1/2"></i><i aria-hidden="true" class="peer/bl absolute bottom-0 left-0 z-10 size-1/2"></i><i aria-hidden="true" class="peer/br absolute bottom-0 right-0 z-10 size-1/2"></i>
      <span aria-hidden="true" class="block text-[clamp(58px,13.5vw,140px)] font-black leading-none tracking-[-0.04em] [text-shadow:0_.06em_.09em_oklch(0.2_0.02_270/0.22)] transition-[transform,text-shadow] duration-500 ease-[cubic-bezier(.2,.8,.25,1)] peer-hover/tl:rotate-x-[11deg] peer-hover/tl:-rotate-y-[13deg] peer-hover/tl:[text-shadow:.07em_.11em_.13em_oklch(0.2_0.02_270/0.42)] peer-hover/tr:rotate-x-[11deg] peer-hover/tr:rotate-y-[13deg] peer-hover/tr:[text-shadow:-.07em_.11em_.13em_oklch(0.2_0.02_270/0.42)] peer-hover/bl:-rotate-x-[11deg] peer-hover/bl:-rotate-y-[13deg] peer-hover/bl:[text-shadow:.07em_-.07em_.13em_oklch(0.2_0.02_270/0.4)] peer-hover/br:-rotate-x-[11deg] peer-hover/br:rotate-y-[13deg] peer-hover/br:[text-shadow:-.07em_-.07em_.13em_oklch(0.2_0.02_270/0.4)] group-focus-visible/tilt:animate-tth22-sway motion-reduce:transition-none motion-reduce:animate-none!">PIVOT<span class="text-tth22-acc">&rsquo;26</span></span>
    </a>
    <p class="max-w-[52ch] text-[15px] leading-[1.7] text-tth22-mut">Approach the wordmark from any corner &mdash; it leans toward you. Four invisible hover quadrants, four poses, one transition blending them. No script.</p>
    <p class="text-[12.5px] text-tth22-mut">The shadow always slides opposite the tilt &mdash; fixed lamp, turning object. <kbd class="rounded-[5px] border border-b-2 border-tth22-line bg-white px-1.5 py-0.5 font-tth22-mono text-[11px]">Tab</kbd> to it for the keyboard sway.</p>
  </div>
</section>
```
## CSS
```css
@import "tailwindcss";

@theme {
  --color-tth22-bg: #eceef3;
  --color-tth22-bg: oklch(0.94 0.006 260);
  --color-tth22-glow: #f6f7fa;
  --color-tth22-glow: oklch(0.975 0.004 260);
  --color-tth22-ink: #1a1c2b;
  --color-tth22-ink: oklch(0.22 0.02 270);
  --color-tth22-mut: #5a5d6c;
  --color-tth22-mut: oklch(0.47 0.015 265);
  --color-tth22-acc: #3c55d8;
  --color-tth22-acc: oklch(0.52 0.2 265);
  --color-tth22-line: #d4d6de;
  --color-tth22-line: oklch(0.86 0.008 260);
  --font-tth22-sans: 'Schibsted Grotesk', system-ui, sans-serif;
  --font-tth22-mono: 'JetBrains Mono', ui-monospace, monospace;
  --animate-tth22-sway: tth22-sway 3.2s ease-in-out infinite;

  @keyframes tth22-sway {
    0%,
        100% {
      transform: rotateX(9deg) rotateY(-11deg);
    }

    50% {
      transform: rotateX(-9deg) rotateY(11deg);
    }
  }
}

.tth-22 {
  width: 100%;
  min-height: 100svh;
}
```

How this works

Hover zones. Four absolutely positioned <i> elements cover the quadrants of the wordmark, above it in z-order. Each is a named peer, and because they come before the word in the DOM, the word can read their hover state:

<i class="peer/tl absolute left-0 top-0 z-10 size-1/2"></i>…
<span class="transition-[transform,text-shadow] duration-500
  peer-hover/tl:rotate-x-[11deg] peer-hover/tl:-rotate-y-[13deg]
  peer-hover/tr:rotate-x-[11deg] peer-hover/tr:rotate-y-[13deg] …">

Blending. Moving from one quadrant to the next swaps targets mid-transition, so the word glides between poses rather than snapping — a cheap approximation of continuous tracking.

Shadow logic. Each pose's shadow offset is the opposite of its tilt, as if a lamp were fixed above the viewer.

Make it yours

  • Stronger tilt: raise 11/13deg to 16/18deg and lower perspective to 650px.
  • Nine zones: a 3×3 grid of peers adds pure X and Y poses.
  • Use on cards: put the same zones over any card and tilt the card body.

Gotchas — read before shipping

  • The zones must be siblings that precede the target — peer-* only looks backwards.
  • Zones sit on top, so they'd swallow clicks on inner links; here the whole wrapper is one link, so clicks still land.
  • Text in 3D can blur during the transition on low-DPI screens; it re-sharpens at rest.

Browser support

ChromeSafariFirefoxEdge
111+16.4+128+111+

3D transforms are universal; the floor is Tailwind v4's sheet.

Techniques used in this demo

Utilitiesfirst-class utility or variant

Search CodeFronts

Loading…