Tailwind v4 3D Transforms: Build a Flip Card With transform-3d and perspective, No JavaScript

Tailwind v4 ships transform-3d, rotate-x/y, perspective and backface-hidden utilities. Build a flip card and a tilt effect in Blade with zero JavaScript.

Steven Richardson
Steven Richardson
· 8 min read

A "flip on hover" pricing card used to mean arbitrary values and a custom CSS block: [transform:rotateY(180deg)] smeared across the markup, @apply rules in a stylesheet, and a mental model nobody on the team shared. Tailwind v4 gives every 3D transform a named utility, so the whole effect lives in your Blade template. This is the recipe the docs never quite assemble end to end: the perspective container, the transform-3d toggle, the two faces, and the hover trigger.

If you are still on Tailwind v3, none of these utilities exist yet — the Tailwind v3 to v4 Laravel upgrade walkthrough is the path to get there. Everything below assumes v4.2 or later.

Set up the perspective container#

3D rotation only looks three-dimensional if the browser knows where the camera is. That is what perspective does, and the catch that trips everyone up is that it belongs on the parent of the element you rotate, not on the element itself. Put perspective-* on the outer wrapper and add group so the inner card can react to hover.

<div class="group perspective-distant size-64">
    <!-- the rotating card goes here -->
</div>

Tailwind's named scale saves you from guessing pixel values. The classes map to fixed distances: perspective-dramatic is 100px (an aggressive, almost fisheye depth), perspective-near 300px, perspective-normal 500px, perspective-midrange 800px, and perspective-distant 1200px (a subtle, far-away camera). Smaller numbers mean a closer camera and a more extreme effect. For a card flip, perspective-distant keeps the rotation believable rather than warped.

Mark the rotating element with transform-3d#

Inside the container, the card needs to preserve 3D space for its children, otherwise the browser collapses the front and back faces onto the same flat plane and the flip turns into a smear. The utility for transform-style: preserve-3d is simply transform-3d — not transform-style-preserve-3d, which is a common guess that silently does nothing. Add the rotation transition here too, since this is the element that actually spins.

<div class="group perspective-distant size-64">
    <div class="relative size-full transition-transform duration-700 transform-3d group-hover:rotate-y-180">
        <!-- front and back faces go here -->
    </div>
</div>

The group-hover:rotate-y-180 is the whole trick: when the user hovers the outer group, the inner card rotates 180 degrees on the Y axis. transition-transform and duration-700 make it a smooth half-second turn instead of an instant snap.

Position the front and back faces#

Both faces have to occupy the same spot so one can sit directly behind the other. Use absolute inset-0 on each, then pre-rotate the back face by 180 degrees so that once the card flips, the back is the side facing you. The front face needs no rotation — it starts pointing at the camera.

<div class="relative size-full transition-transform duration-700 transform-3d group-hover:rotate-y-180">
    <!-- Front -->
    <div class="absolute inset-0 grid place-items-center rounded-2xl bg-white shadow-lg">
        <span class="text-xl font-semibold">£29 / month</span>
    </div>

    <!-- Back, pre-rotated so it reads correctly after the flip -->
    <div class="absolute inset-0 grid place-items-center rounded-2xl bg-sky-600 text-white rotate-y-180">
        <span class="text-lg">Start your trial →</span>
    </div>
</div>

Style the faces however you like — a Tailwind v4 gradient background on the back face reads especially well, because the saturated colour sells the reveal. At this point the card flips, but you will notice the back of the front face ghosting through. That is the next step.

Hide the backface to stop visual bleed#

When a face rotates away from the camera, browsers render its mirror-reversed back side by default. During the flip you see the front face's reverse — text backwards, colours muddy — peeking through the real back face. backface-hidden (which maps to backface-visibility: hidden) tells the browser not to paint the reverse side of an element at all. Add it to both faces.

<!-- Front -->
<div class="absolute inset-0 grid place-items-center rounded-2xl bg-white shadow-lg backface-hidden">
    <span class="text-xl font-semibold">£29 / month</span>
</div>

<!-- Back -->
<div class="absolute inset-0 grid place-items-center rounded-2xl bg-sky-600 text-white rotate-y-180 backface-hidden">
    <span class="text-lg">Start your trial →</span>
</div>

With backface-hidden on both faces, only the face currently pointing at the camera renders. The flip is now clean: front turns away, back turns in, no ghosting in between.

Trigger the flip on hover with group-hover#

The flip is already wired through group-hover:rotate-y-180 on the rotating element, so there is no JavaScript to add — the entire interaction is the group / group-hover: pair. Here is the complete, copy-paste card with every piece in place.

<div class="group perspective-distant size-64">
    <div class="relative size-full transition-transform duration-700 ease-out transform-3d group-hover:rotate-y-180">
        <div class="absolute inset-0 grid place-items-center rounded-2xl bg-white shadow-lg backface-hidden">
            <span class="text-xl font-semibold">£29 / month</span>
        </div>
        <div class="absolute inset-0 grid place-items-center rounded-2xl bg-sky-600 text-white rotate-y-180 backface-hidden">
            <span class="text-lg">Start your trial →</span>
        </div>
    </div>
</div>

Because the flip is pure CSS, it composes with the rest of Tailwind's state system. If you want the same no-JavaScript discipline for elements that enter and leave the page, the Tailwind v4 starting-style and transition-discrete recipe animates display: none without a line of Alpine.

Add a tilt-on-hover variant#

The same primitives give you a subtler effect with far less markup. Drop the two-face setup and rotate a single card a few degrees on both axes when hovered. This is the "interactive product card" tilt you see on marketing sites, and it is two utility classes plus a transition.

<div class="perspective-near">
    <div class="size-64 rounded-2xl bg-white shadow-xl transition-transform duration-300 ease-out transform-3d hover:rotate-x-6 hover:rotate-y-6">
        <!-- card content -->
    </div>
</div>

Here perspective-near (300px) makes the tilt feel close and tactile, while small rotate-x-6 and rotate-y-6 angles keep it tasteful. Pair the tilt with container queries so the card resizes to its slot rather than the viewport, and the same component drops cleanly into a sidebar or a wide grid.

Gotchas and Edge Cases#

The single most common failure is forgetting transform-3d on the rotating element. Without it, transform-style defaults to flat, the browser projects both faces onto one plane, and your flip looks like a crossfade. If your card animates but never shows depth, that missing class is almost always why.

The second is putting perspective-* on the wrong element. Perspective applies to the children of the element it is set on, so it has to live on the parent wrapper. Set perspective-distant on the inner rotating card and you will get a flat rotation with no foreshortening at all.

Watch overflow too. A parent with overflow-hidden will clip the card mid-rotation as it sweeps through Z space, producing an ugly hard edge. Keep the perspective container overflow-visible, or give it enough padding that the rotation never reaches the boundary. The same caution applies if you stack a text-shadow for depth on the card heading — shadows can spill past a tight clip box.

Finally, this is modern-evergreen only. The 3D transform properties have shipped in Chrome, Edge, Safari, and Firefox for years, so there is no real-world support gap, but a browser that ignores the transform simply shows the front face with no flip. That is a graceful fallback, not a broken layout — the card is still readable and clickable.

Wrapping Up#

Start with the full flip card above, swap in your own face content, and tune duration-700 until the turn feels right for your brand. Reach for the tilt variant when you want motion without a second face. Both are pure CSS, both compose with Tailwind's variant system, and neither needs a line of JavaScript. From here, the Tailwind v4 mask utilities for image fade and reveal effects and the container query patterns for responsive components are the natural next utilities to layer onto these cards.

FAQ#

What are the new 3D transform utilities in Tailwind v4?

Tailwind v4 added a complete 3D transform set: transform-3d and transform-flat for transform-style, rotate-x-*, rotate-y-* and rotate-z-* for axis rotation, perspective-* and perspective-origin-* for the camera, and backface-hidden / backface-visible for backface visibility. Together they cover the effects that previously required custom CSS or a plugin.

How do I use perspective in Tailwind CSS?

Add a perspective-* utility to the parent of the element you want to rotate, not the element itself. Tailwind ships a named scale — perspective-dramatic, perspective-near, perspective-normal, perspective-midrange and perspective-distant — running from 100px to 1200px. Smaller values place the camera closer and exaggerate the depth; larger values are subtler.

What is transform-3d in Tailwind v4?

transform-3d is the utility for the CSS transform-style: preserve-3d declaration. It tells the browser to keep an element's children positioned in 3D space rather than flattening them onto a single plane. It is required on the element whose children you rotate in 3D — without it, a flip card collapses into a flat crossfade.

How do I build a card flip animation with Tailwind?

Wrap the card in a group perspective-distant container, give the inner card transform-3d transition-transform duration-700 group-hover:rotate-y-180, then stack a front and back face with absolute inset-0 and backface-hidden. Pre-rotate the back face with rotate-y-180 so it reads correctly after the flip. The whole effect is CSS-only — no JavaScript required.

What does backface-hidden do?

backface-hidden maps to backface-visibility: hidden, which stops the browser painting the mirror-reversed back side of an element when it rotates away from the camera. On a flip card it prevents the reverse of the front face ghosting through the real back face during the turn, keeping the animation clean.

Do Tailwind v4 3D transforms work with group-hover?

Yes. The 3D rotation utilities are ordinary transform utilities, so every Tailwind variant applies — including group-hover:, hover:, focus: and responsive prefixes like md:. A flip card is built precisely by putting group on the perspective container and group-hover:rotate-y-180 on the rotating element.

Steven Richardson
Steven Richardson

CTO at Digitonic. Writing about Laravel, architecture, and the craft of leading software teams from the west coast of Scotland.