25 Tailwind CSS Button Groups
20 / 25

All 25 in 25 Tailwind CSS Button Groups

  1. 01Tailwind Split Button with Anchor-Positioned Popover Dropdown (No JS)
  2. 02Tailwind Segmented Control with Motion-Path Comet Indicator
  3. 03Tailwind Toggle Button Group with View Transitions Morphing Highlight
  4. 04Tailwind Pricing Toggle — Monthly / Yearly Billing Switch (No JS)
  5. 05Tailwind Segmented Control with Sliding Thumb (iOS Style)
  6. 06Tailwind Split Button Dropdown with Native Details Menu (Save Options)
  7. 07Tailwind Icon Button Group Toolbar with Tooltips (Rich Text Editor)
  8. 08Tailwind Pill Filter Button Group with Sliding Indicator (Anchor Positioning)
  9. 09Tailwind Toggle Button Group for Text Alignment (Radio Inputs, Live Preview)
  10. 10Tailwind Web3 Connect Wallet Button Grid (Wallet Sign-In Modal)
  11. 11Tailwind AI Model Selector Button Group (LLM Model Picker with Badges)
  12. 12Tailwind Liquid Metal Segmented Control (Animated Chrome Thumb)
  13. 13Tailwind Tab Button Group with Subgrid Underline Indicator
  14. 14Tailwind Multi-Select Chip Buttons (Tag Filter Checkboxes with Count)
  15. 15Tailwind Animated Split Button Deploy Menu (Staggered Dropdown Reveal)
  16. 16Tailwind Radio Button Group with Conic Fill Animation (Export Format Picker)
  17. 17Tailwind Retro LED Pixel Button Group (Dot-Matrix Display Buttons)
  18. 18Tailwind Hold-to-Confirm Button Group with Gradient Progress (Press and Hold)
  19. 19Tailwind Holographic Icon Segmented Control (Grid / List View Switcher)
  20. 20Tailwind 3D Vertical Button Group with Hover Depth (Perspective Stack)
  21. 21Tailwind Floating Action Button with Radial Speed Dial Menu (No JS)
  22. 22Tailwind Glitch Effect Button Group (Cyberpunk RGB-Split Audio Filter)
  23. 23Tailwind Animated Gradient Border Pill Buttons (Rotating Conic Ring)
  24. 24Tailwind Button Group with Ripple Click Effect (Radar Shockwave Feedback)
  25. 25Tailwind Button Group with Cursor-Following Spotlight Glow (Date Range Presets)
Pure TailwindMIT licensed

Tailwind 3D Vertical Button Group with Hover Depth (Perspective Stack)

A vertical navigation stack tilted into 3D, where the hovered (or keyboard-focused) card lifts toward you while its siblings sink back and dim. It's a showcase for v4's native 3D utilities — perspective-[760px], transform-3d, rotate-x-34, translate-z-[70px] — combined with group-has-[button:hover]/stack:not-hover:, which targets “every card except the one under the pointer” in one variant.

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="tbg-20 w-full min-h-svh grid place-items-center bg-tbg20-bg bg-linear-165 from-tbg20-bg to-tbg20-bg2 px-5 py-14 font-tbg20-sans text-tbg20-ink" aria-label="3D hover depth vertical button group demo">
  <nav aria-label="Workspace" class="perspective-[760px] perspective-origin-[50%_42%]">
    <div class="group/stack flex w-[min(21rem,86vw)] flex-col gap-4.5 transform-3d rotate-x-34 -rotate-z-1 motion-reduce:transform-none">
      <button type="button" aria-current="page" style="--c:#ff8a4c" class="flex cursor-pointer items-center gap-4 rounded-2xl border-l-4 border-(--c) bg-linear-to-b from-tbg20-card to-tbg20-card2 px-5.5 py-4.5 text-left shadow-tbg20-card transform-3d transition-[translate,rotate,opacity,filter,box-shadow] duration-400 ease-[cubic-bezier(.34,1.4,.4,1)] hover:translate-z-[70px] hover:-rotate-x-14 hover:shadow-[0_40px_60px_-24px_rgb(0_0_0/0.9),0_0_0_1px_var(--c)] focus-visible:translate-z-[70px] focus-visible:-rotate-x-14 focus-visible:shadow-[0_40px_60px_-24px_rgb(0_0_0/0.9),0_0_0_3px_var(--c)] focus-visible:outline-none group-has-[button:hover]/stack:not-hover:-translate-z-[55px] group-has-[button:hover]/stack:not-hover:opacity-50 group-has-[button:hover]/stack:not-hover:brightness-75 group-has-[button:focus-visible]/stack:not-focus-visible:-translate-z-[55px] group-has-[button:focus-visible]/stack:not-focus-visible:opacity-50 motion-reduce:transform-none! motion-reduce:transition-opacity">
        <span aria-hidden="true" class="grid size-10 flex-none place-items-center rounded-xl bg-(--c)/15 text-(--c)"><svg viewBox="0 0 24 24" width="19" height="19" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linejoin="round"><rect x="4" y="4" width="7" height="9" rx="1.5"/><rect x="13" y="4" width="7" height="5" rx="1.5"/><rect x="13" y="11" width="7" height="9" rx="1.5"/><rect x="4" y="15" width="7" height="5" rx="1.5"/></svg></span>
        <span class="grid gap-0.5"><span class="text-[17px] font-extrabold tracking-[-0.01em]">Dashboard</span><span class="text-[13px] text-tbg20-mut">Overview &amp; metrics</span></span>
        <span class="ml-auto rounded-full bg-(--c)/15 px-2 py-0.5 text-[11px] font-bold text-(--c)">Current</span>
      </button>
      <button type="button" style="--c:#ffd24c" class="flex cursor-pointer items-center gap-4 rounded-2xl border-l-4 border-(--c) bg-linear-to-b from-tbg20-card to-tbg20-card2 px-5.5 py-4.5 text-left shadow-tbg20-card transform-3d transition-[translate,rotate,opacity,filter,box-shadow] duration-400 ease-[cubic-bezier(.34,1.4,.4,1)] hover:translate-z-[70px] hover:-rotate-x-14 hover:shadow-[0_40px_60px_-24px_rgb(0_0_0/0.9),0_0_0_1px_var(--c)] focus-visible:translate-z-[70px] focus-visible:-rotate-x-14 focus-visible:shadow-[0_40px_60px_-24px_rgb(0_0_0/0.9),0_0_0_3px_var(--c)] focus-visible:outline-none group-has-[button:hover]/stack:not-hover:-translate-z-[55px] group-has-[button:hover]/stack:not-hover:opacity-50 group-has-[button:hover]/stack:not-hover:brightness-75 group-has-[button:focus-visible]/stack:not-focus-visible:-translate-z-[55px] group-has-[button:focus-visible]/stack:not-focus-visible:opacity-50 motion-reduce:transform-none! motion-reduce:transition-opacity">
        <span aria-hidden="true" class="grid size-10 flex-none place-items-center rounded-xl bg-(--c)/15 text-(--c)"><svg viewBox="0 0 24 24" width="19" height="19" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linejoin="round"><path d="M3 7a2 2 0 0 1 2-2h4l2 2h8a2 2 0 0 1 2 2v8a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z"/></svg></span>
        <span class="grid gap-0.5"><span class="text-[17px] font-extrabold tracking-[-0.01em]">Projects</span><span class="text-[13px] text-tbg20-mut">12 active</span></span>
      </button>
      <button type="button" style="--c:#6ee7a8" class="flex cursor-pointer items-center gap-4 rounded-2xl border-l-4 border-(--c) bg-linear-to-b from-tbg20-card to-tbg20-card2 px-5.5 py-4.5 text-left shadow-tbg20-card transform-3d transition-[translate,rotate,opacity,filter,box-shadow] duration-400 ease-[cubic-bezier(.34,1.4,.4,1)] hover:translate-z-[70px] hover:-rotate-x-14 hover:shadow-[0_40px_60px_-24px_rgb(0_0_0/0.9),0_0_0_1px_var(--c)] focus-visible:translate-z-[70px] focus-visible:-rotate-x-14 focus-visible:shadow-[0_40px_60px_-24px_rgb(0_0_0/0.9),0_0_0_3px_var(--c)] focus-visible:outline-none group-has-[button:hover]/stack:not-hover:-translate-z-[55px] group-has-[button:hover]/stack:not-hover:opacity-50 group-has-[button:hover]/stack:not-hover:brightness-75 group-has-[button:focus-visible]/stack:not-focus-visible:-translate-z-[55px] group-has-[button:focus-visible]/stack:not-focus-visible:opacity-50 motion-reduce:transform-none! motion-reduce:transition-opacity">
        <span aria-hidden="true" class="grid size-10 flex-none place-items-center rounded-xl bg-(--c)/15 text-(--c)"><svg viewBox="0 0 24 24" width="19" height="19" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round"><circle cx="9" cy="8" r="3.2"/><path d="M3.5 20a5.5 5.5 0 0 1 11 0M16 5.5a3 3 0 0 1 0 5.5M18 20a5 5 0 0 0-2.5-4.3"/></svg></span>
        <span class="grid gap-0.5"><span class="text-[17px] font-extrabold tracking-[-0.01em]">Team</span><span class="text-[13px] text-tbg20-mut">8 members</span></span>
      </button>
      <button type="button" style="--c:#5cc8ff" class="flex cursor-pointer items-center gap-4 rounded-2xl border-l-4 border-(--c) bg-linear-to-b from-tbg20-card to-tbg20-card2 px-5.5 py-4.5 text-left shadow-tbg20-card transform-3d transition-[translate,rotate,opacity,filter,box-shadow] duration-400 ease-[cubic-bezier(.34,1.4,.4,1)] hover:translate-z-[70px] hover:-rotate-x-14 hover:shadow-[0_40px_60px_-24px_rgb(0_0_0/0.9),0_0_0_1px_var(--c)] focus-visible:translate-z-[70px] focus-visible:-rotate-x-14 focus-visible:shadow-[0_40px_60px_-24px_rgb(0_0_0/0.9),0_0_0_3px_var(--c)] focus-visible:outline-none group-has-[button:hover]/stack:not-hover:-translate-z-[55px] group-has-[button:hover]/stack:not-hover:opacity-50 group-has-[button:hover]/stack:not-hover:brightness-75 group-has-[button:focus-visible]/stack:not-focus-visible:-translate-z-[55px] group-has-[button:focus-visible]/stack:not-focus-visible:opacity-50 motion-reduce:transform-none! motion-reduce:transition-opacity">
        <span aria-hidden="true" class="grid size-10 flex-none place-items-center rounded-xl bg-(--c)/15 text-(--c)"><svg viewBox="0 0 24 24" width="19" height="19" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round"><circle cx="12" cy="12" r="3"/><path d="M12 3v3M12 18v3M3 12h3M18 12h3M5.6 5.6l2.1 2.1M16.3 16.3l2.1 2.1M5.6 18.4l2.1-2.1M16.3 7.7l2.1-2.1"/></svg></span>
        <span class="grid gap-0.5"><span class="text-[17px] font-extrabold tracking-[-0.01em]">Settings</span><span class="text-[13px] text-tbg20-mut">Workspace config</span></span>
      </button>
    </div>
  </nav>
</section>
@import "tailwindcss";

@theme {
  --color-tbg20-bg: #2a1c14;
  --color-tbg20-bg2: #160f0a;
  --color-tbg20-card: #35291e;
  --color-tbg20-card2: #241a12;
  --color-tbg20-ink: #f6eadb;
  --color-tbg20-mut: #c4ab93;
  --color-tbg20-mut: oklch(0.76 0.05 65);
  --shadow-tbg20-card: 0 16px 30px -14px rgb(0 0 0 / 0.85), inset 0 1px 0 rgb(255 255 255 / 0.08);
  --font-tbg20-sans: 'Schibsted Grotesk', system-ui, sans-serif;
}
/* Root rule: the full-bleed contract, restated so the stage is sized before the browser build compiles. */

.tbg-20 {
  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-tbg20-bg: #2a1c14;
  --color-tbg20-bg2: #160f0a;
  --color-tbg20-card: #35291e;
  --color-tbg20-card2: #241a12;
  --color-tbg20-ink: #f6eadb;
  --color-tbg20-mut: #c4ab93;
  --color-tbg20-mut: oklch(0.76 0.05 65);
  --shadow-tbg20-card: 0 16px 30px -14px rgb(0 0 0 / 0.85), inset 0 1px 0 rgb(255 255 255 / 0.08);
  --font-tbg20-sans: 'Schibsted Grotesk', system-ui, sans-serif;
}
/* Root rule: the full-bleed contract, restated so the stage is sized before the browser build compiles. */

.tbg-20 {
  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..800&display=swap">

What changed in the port

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

  • transform:rotateX(34deg) rotateZ(-1deg) and translateZ(70px) rotateX(-14deg) became v4's individual 3D utilities (rotate-x-34, translate-z-[70px], -rotate-x-14).
  • The :has(.btn:hover) .btn:not(:hover) sibling-dim rule became one variant chain: group-has-[button:hover]/stack:not-hover:.
  • UI upgrade: each card gained an icon tile in its accent colour, the current section is marked with aria-current and a “Current” badge, and the stack is a labelled <nav>.
  • UI upgrade: sub-labels rose from #b39a83 to oklch(0.76) (6.8:1 on the card).
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 Vertical Button Group with Hover Depth (Perspective Stack)
Source: https://codefronts.com/components/tailwind-css-button-groups/tailwind-3d-vertical-button-group-hover/

A vertical navigation stack tilted into 3D, where the hovered (or keyboard-focused) card lifts toward you while its siblings sink back and dim. It's a showcase for v4's native 3D utilities &mdash; perspective-[760px], transform-3d, rotate-x-34, translate-z-[70px] &mdash; combined with group-has-[button:hover]/stack:not-hover:, which targets &ldquo;every card except the one under the pointer&rdquo; in one variant.
## HTML
```html
<section class="tbg-20 w-full min-h-svh grid place-items-center bg-tbg20-bg bg-linear-165 from-tbg20-bg to-tbg20-bg2 px-5 py-14 font-tbg20-sans text-tbg20-ink" aria-label="3D hover depth vertical button group demo">
  <nav aria-label="Workspace" class="perspective-[760px] perspective-origin-[50%_42%]">
    <div class="group/stack flex w-[min(21rem,86vw)] flex-col gap-4.5 transform-3d rotate-x-34 -rotate-z-1 motion-reduce:transform-none">
      <button type="button" aria-current="page" style="--c:#ff8a4c" class="flex cursor-pointer items-center gap-4 rounded-2xl border-l-4 border-(--c) bg-linear-to-b from-tbg20-card to-tbg20-card2 px-5.5 py-4.5 text-left shadow-tbg20-card transform-3d transition-[translate,rotate,opacity,filter,box-shadow] duration-400 ease-[cubic-bezier(.34,1.4,.4,1)] hover:translate-z-[70px] hover:-rotate-x-14 hover:shadow-[0_40px_60px_-24px_rgb(0_0_0/0.9),0_0_0_1px_var(--c)] focus-visible:translate-z-[70px] focus-visible:-rotate-x-14 focus-visible:shadow-[0_40px_60px_-24px_rgb(0_0_0/0.9),0_0_0_3px_var(--c)] focus-visible:outline-none group-has-[button:hover]/stack:not-hover:-translate-z-[55px] group-has-[button:hover]/stack:not-hover:opacity-50 group-has-[button:hover]/stack:not-hover:brightness-75 group-has-[button:focus-visible]/stack:not-focus-visible:-translate-z-[55px] group-has-[button:focus-visible]/stack:not-focus-visible:opacity-50 motion-reduce:transform-none! motion-reduce:transition-opacity">
        <span aria-hidden="true" class="grid size-10 flex-none place-items-center rounded-xl bg-(--c)/15 text-(--c)"><svg viewBox="0 0 24 24" width="19" height="19" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linejoin="round"><rect x="4" y="4" width="7" height="9" rx="1.5"/><rect x="13" y="4" width="7" height="5" rx="1.5"/><rect x="13" y="11" width="7" height="9" rx="1.5"/><rect x="4" y="15" width="7" height="5" rx="1.5"/></svg></span>
        <span class="grid gap-0.5"><span class="text-[17px] font-extrabold tracking-[-0.01em]">Dashboard</span><span class="text-[13px] text-tbg20-mut">Overview &amp; metrics</span></span>
        <span class="ml-auto rounded-full bg-(--c)/15 px-2 py-0.5 text-[11px] font-bold text-(--c)">Current</span>
      </button>
      <button type="button" style="--c:#ffd24c" class="flex cursor-pointer items-center gap-4 rounded-2xl border-l-4 border-(--c) bg-linear-to-b from-tbg20-card to-tbg20-card2 px-5.5 py-4.5 text-left shadow-tbg20-card transform-3d transition-[translate,rotate,opacity,filter,box-shadow] duration-400 ease-[cubic-bezier(.34,1.4,.4,1)] hover:translate-z-[70px] hover:-rotate-x-14 hover:shadow-[0_40px_60px_-24px_rgb(0_0_0/0.9),0_0_0_1px_var(--c)] focus-visible:translate-z-[70px] focus-visible:-rotate-x-14 focus-visible:shadow-[0_40px_60px_-24px_rgb(0_0_0/0.9),0_0_0_3px_var(--c)] focus-visible:outline-none group-has-[button:hover]/stack:not-hover:-translate-z-[55px] group-has-[button:hover]/stack:not-hover:opacity-50 group-has-[button:hover]/stack:not-hover:brightness-75 group-has-[button:focus-visible]/stack:not-focus-visible:-translate-z-[55px] group-has-[button:focus-visible]/stack:not-focus-visible:opacity-50 motion-reduce:transform-none! motion-reduce:transition-opacity">
        <span aria-hidden="true" class="grid size-10 flex-none place-items-center rounded-xl bg-(--c)/15 text-(--c)"><svg viewBox="0 0 24 24" width="19" height="19" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linejoin="round"><path d="M3 7a2 2 0 0 1 2-2h4l2 2h8a2 2 0 0 1 2 2v8a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z"/></svg></span>
        <span class="grid gap-0.5"><span class="text-[17px] font-extrabold tracking-[-0.01em]">Projects</span><span class="text-[13px] text-tbg20-mut">12 active</span></span>
      </button>
      <button type="button" style="--c:#6ee7a8" class="flex cursor-pointer items-center gap-4 rounded-2xl border-l-4 border-(--c) bg-linear-to-b from-tbg20-card to-tbg20-card2 px-5.5 py-4.5 text-left shadow-tbg20-card transform-3d transition-[translate,rotate,opacity,filter,box-shadow] duration-400 ease-[cubic-bezier(.34,1.4,.4,1)] hover:translate-z-[70px] hover:-rotate-x-14 hover:shadow-[0_40px_60px_-24px_rgb(0_0_0/0.9),0_0_0_1px_var(--c)] focus-visible:translate-z-[70px] focus-visible:-rotate-x-14 focus-visible:shadow-[0_40px_60px_-24px_rgb(0_0_0/0.9),0_0_0_3px_var(--c)] focus-visible:outline-none group-has-[button:hover]/stack:not-hover:-translate-z-[55px] group-has-[button:hover]/stack:not-hover:opacity-50 group-has-[button:hover]/stack:not-hover:brightness-75 group-has-[button:focus-visible]/stack:not-focus-visible:-translate-z-[55px] group-has-[button:focus-visible]/stack:not-focus-visible:opacity-50 motion-reduce:transform-none! motion-reduce:transition-opacity">
        <span aria-hidden="true" class="grid size-10 flex-none place-items-center rounded-xl bg-(--c)/15 text-(--c)"><svg viewBox="0 0 24 24" width="19" height="19" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round"><circle cx="9" cy="8" r="3.2"/><path d="M3.5 20a5.5 5.5 0 0 1 11 0M16 5.5a3 3 0 0 1 0 5.5M18 20a5 5 0 0 0-2.5-4.3"/></svg></span>
        <span class="grid gap-0.5"><span class="text-[17px] font-extrabold tracking-[-0.01em]">Team</span><span class="text-[13px] text-tbg20-mut">8 members</span></span>
      </button>
      <button type="button" style="--c:#5cc8ff" class="flex cursor-pointer items-center gap-4 rounded-2xl border-l-4 border-(--c) bg-linear-to-b from-tbg20-card to-tbg20-card2 px-5.5 py-4.5 text-left shadow-tbg20-card transform-3d transition-[translate,rotate,opacity,filter,box-shadow] duration-400 ease-[cubic-bezier(.34,1.4,.4,1)] hover:translate-z-[70px] hover:-rotate-x-14 hover:shadow-[0_40px_60px_-24px_rgb(0_0_0/0.9),0_0_0_1px_var(--c)] focus-visible:translate-z-[70px] focus-visible:-rotate-x-14 focus-visible:shadow-[0_40px_60px_-24px_rgb(0_0_0/0.9),0_0_0_3px_var(--c)] focus-visible:outline-none group-has-[button:hover]/stack:not-hover:-translate-z-[55px] group-has-[button:hover]/stack:not-hover:opacity-50 group-has-[button:hover]/stack:not-hover:brightness-75 group-has-[button:focus-visible]/stack:not-focus-visible:-translate-z-[55px] group-has-[button:focus-visible]/stack:not-focus-visible:opacity-50 motion-reduce:transform-none! motion-reduce:transition-opacity">
        <span aria-hidden="true" class="grid size-10 flex-none place-items-center rounded-xl bg-(--c)/15 text-(--c)"><svg viewBox="0 0 24 24" width="19" height="19" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round"><circle cx="12" cy="12" r="3"/><path d="M12 3v3M12 18v3M3 12h3M18 12h3M5.6 5.6l2.1 2.1M16.3 16.3l2.1 2.1M5.6 18.4l2.1-2.1M16.3 7.7l2.1-2.1"/></svg></span>
        <span class="grid gap-0.5"><span class="text-[17px] font-extrabold tracking-[-0.01em]">Settings</span><span class="text-[13px] text-tbg20-mut">Workspace config</span></span>
      </button>
    </div>
  </nav>
</section>
```
## CSS
```css
@import "tailwindcss";

@theme {
  --color-tbg20-bg: #2a1c14;
  --color-tbg20-bg2: #160f0a;
  --color-tbg20-card: #35291e;
  --color-tbg20-card2: #241a12;
  --color-tbg20-ink: #f6eadb;
  --color-tbg20-mut: #c4ab93;
  --color-tbg20-mut: oklch(0.76 0.05 65);
  --shadow-tbg20-card: 0 16px 30px -14px rgb(0 0 0 / 0.85), inset 0 1px 0 rgb(255 255 255 / 0.08);
  --font-tbg20-sans: 'Schibsted Grotesk', system-ui, sans-serif;
}
/* Root rule: the full-bleed contract, restated so the stage is sized before the browser build compiles. */

.tbg-20 {
  width: 100%;
  min-height: 100svh;
}
```

How this works

v4 ships 3D. No arbitrary transforms needed:

<div class="perspective-[760px]">
  <div class="group/stack transform-3d rotate-x-34 -rotate-z-1">
    <button class="hover:translate-z-[70px] hover:-rotate-x-14
      group-has-[button:hover]/stack:not-hover:-translate-z-[55px]
      group-has-[button:hover]/stack:not-hover:opacity-50">

Focus gets the same depth. Each hover rule has a focus-visible twin, so keyboard users see the same lift, and the outline is replaced by a ring in the card's own colour.

Make it yours

  • Flatter: rotate-x-20 and hover:translate-z-[40px].
  • Horizontal row: flex-row and rotate-y-[-20deg] instead of rotate-x.
  • Card colour: each button's inline --c.

Gotchas — read before shipping

  • transform-3d (preserve-3d) is flattened by overflow-hidden, opacity on a parent or filter — keep those off the stack element.
  • Tilted text is harder to read; keep labels short and large.
  • Reduced motion removes the tilt entirely and keeps only the dimming.

Browser support

ChromeSafariFirefoxEdge
111+16.4+128+111+

3D transforms are universal; v4's individual rotate-x-*/translate-z-* utilities need Tailwind v4.

Techniques used in this demo

Utilitiesfirst-class utility or variant

Search CodeFronts

Loading…