Pure TailwindMIT licensed

Tailwind 3D Coverflow Carousel with Perspective Transforms

The Cover Flow effect: the centre image faces you full-size while the flanking covers tilt back in 3D. Tailwind v4 added real perspective-*, transform-3d and rotate-y-* utilities, so the 3D is native — but this is also the one demo where the port relocates complexity rather than removing it.

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="tcar-13 w-full min-h-svh grid place-items-center bg-tcar13-bg font-tcar13-sans px-5 py-10" aria-label="Album coverflow">
  <div class="group w-[min(560px,100%)] perspective-[1200px]">
    <input type="radio" name="tcar-13" id="tcar-13-1" class="sr-only">
    <input type="radio" name="tcar-13" id="tcar-13-2" class="sr-only">
    <input type="radio" name="tcar-13" id="tcar-13-3" class="sr-only" checked>
    <input type="radio" name="tcar-13" id="tcar-13-4" class="sr-only">
    <input type="radio" name="tcar-13" id="tcar-13-5" class="sr-only">
    <div class="relative h-[300px] transform-3d">
      <figure class="absolute top-1/2 left-1/2 size-[220px] -mt-[110px] -ml-[110px] m-0 rounded-[10px] overflow-hidden transform-3d opacity-55 shadow-[0_24px_40px_-20px_oklch(0_0_0/0.8)] transition-[translate,scale,opacity,transform] duration-500 ease-[cubic-bezier(0.2,0.8,0.2,1)] group-has-[#tcar-13-1:checked]:translate-x-0 group-has-[#tcar-13-1:checked]:rotate-y-0 group-has-[#tcar-13-1:checked]:scale-100 group-has-[#tcar-13-1:checked]:opacity-100 group-has-[#tcar-13-1:checked]:z-[5] group-has-[#tcar-13-2:checked]:-translate-x-[120px] group-has-[#tcar-13-2:checked]:rotate-y-[42deg] group-has-[#tcar-13-2:checked]:scale-[0.82] group-has-[#tcar-13-2:checked]:opacity-75 group-has-[#tcar-13-2:checked]:z-[4] group-has-[#tcar-13-3:checked]:-translate-x-[210px] group-has-[#tcar-13-3:checked]:rotate-y-[48deg] group-has-[#tcar-13-3:checked]:scale-[0.66] group-has-[#tcar-13-3:checked]:z-[3] group-has-[#tcar-13-4:checked]:-translate-x-[285px] group-has-[#tcar-13-4:checked]:rotate-y-[52deg] group-has-[#tcar-13-4:checked]:scale-[0.52] group-has-[#tcar-13-4:checked]:opacity-35 group-has-[#tcar-13-4:checked]:z-[2] group-has-[#tcar-13-5:checked]:-translate-x-[345px] group-has-[#tcar-13-5:checked]:rotate-y-[54deg] group-has-[#tcar-13-5:checked]:scale-[0.42] group-has-[#tcar-13-5:checked]:opacity-20 group-has-[#tcar-13-5:checked]:z-[1] group-has-[#tcar-13-1:focus-visible]:outline-3 group-has-[#tcar-13-1:focus-visible]:outline-tcar13-acc group-has-[#tcar-13-1:focus-visible]:outline-offset-4 motion-reduce:transition-none">
        <img src="https://picsum.photos/seed/cover-1/500/500" width="500" height="500" loading="lazy" decoding="async" alt="Album: Nocturne" class="size-full object-cover block pointer-events-none"><label for="tcar-13-1" aria-label="Show cover 1" class="absolute inset-0 cursor-pointer"></label>
      </figure>
      <figure class="absolute top-1/2 left-1/2 size-[220px] -mt-[110px] -ml-[110px] m-0 rounded-[10px] overflow-hidden transform-3d opacity-55 shadow-[0_24px_40px_-20px_oklch(0_0_0/0.8)] transition-[translate,scale,opacity,transform] duration-500 ease-[cubic-bezier(0.2,0.8,0.2,1)] group-has-[#tcar-13-1:checked]:translate-x-[120px] group-has-[#tcar-13-1:checked]:rotate-y-[-42deg] group-has-[#tcar-13-1:checked]:scale-[0.82] group-has-[#tcar-13-1:checked]:opacity-75 group-has-[#tcar-13-1:checked]:z-[4] group-has-[#tcar-13-2:checked]:translate-x-0 group-has-[#tcar-13-2:checked]:rotate-y-0 group-has-[#tcar-13-2:checked]:scale-100 group-has-[#tcar-13-2:checked]:opacity-100 group-has-[#tcar-13-2:checked]:z-[5] group-has-[#tcar-13-3:checked]:-translate-x-[120px] group-has-[#tcar-13-3:checked]:rotate-y-[42deg] group-has-[#tcar-13-3:checked]:scale-[0.82] group-has-[#tcar-13-3:checked]:opacity-75 group-has-[#tcar-13-3:checked]:z-[4] group-has-[#tcar-13-4:checked]:-translate-x-[210px] group-has-[#tcar-13-4:checked]:rotate-y-[48deg] group-has-[#tcar-13-4:checked]:scale-[0.66] group-has-[#tcar-13-4:checked]:z-[3] group-has-[#tcar-13-5:checked]:-translate-x-[285px] group-has-[#tcar-13-5:checked]:rotate-y-[52deg] group-has-[#tcar-13-5:checked]:scale-[0.52] group-has-[#tcar-13-5:checked]:opacity-35 group-has-[#tcar-13-5:checked]:z-[2] group-has-[#tcar-13-2:focus-visible]:outline-3 group-has-[#tcar-13-2:focus-visible]:outline-tcar13-acc group-has-[#tcar-13-2:focus-visible]:outline-offset-4 motion-reduce:transition-none">
        <img src="https://picsum.photos/seed/cover-2/500/500" width="500" height="500" loading="lazy" decoding="async" alt="Album: Parallel" class="size-full object-cover block pointer-events-none"><label for="tcar-13-2" aria-label="Show cover 2" class="absolute inset-0 cursor-pointer"></label>
      </figure>
      <figure class="absolute top-1/2 left-1/2 size-[220px] -mt-[110px] -ml-[110px] m-0 rounded-[10px] overflow-hidden transform-3d opacity-55 shadow-[0_24px_40px_-20px_oklch(0_0_0/0.8)] transition-[translate,scale,opacity,transform] duration-500 ease-[cubic-bezier(0.2,0.8,0.2,1)] group-has-[#tcar-13-1:checked]:translate-x-[210px] group-has-[#tcar-13-1:checked]:rotate-y-[-48deg] group-has-[#tcar-13-1:checked]:scale-[0.66] group-has-[#tcar-13-1:checked]:z-[3] group-has-[#tcar-13-2:checked]:translate-x-[120px] group-has-[#tcar-13-2:checked]:rotate-y-[-42deg] group-has-[#tcar-13-2:checked]:scale-[0.82] group-has-[#tcar-13-2:checked]:opacity-75 group-has-[#tcar-13-2:checked]:z-[4] group-has-[#tcar-13-3:checked]:translate-x-0 group-has-[#tcar-13-3:checked]:rotate-y-0 group-has-[#tcar-13-3:checked]:scale-100 group-has-[#tcar-13-3:checked]:opacity-100 group-has-[#tcar-13-3:checked]:z-[5] group-has-[#tcar-13-4:checked]:-translate-x-[120px] group-has-[#tcar-13-4:checked]:rotate-y-[42deg] group-has-[#tcar-13-4:checked]:scale-[0.82] group-has-[#tcar-13-4:checked]:opacity-75 group-has-[#tcar-13-4:checked]:z-[4] group-has-[#tcar-13-5:checked]:-translate-x-[210px] group-has-[#tcar-13-5:checked]:rotate-y-[48deg] group-has-[#tcar-13-5:checked]:scale-[0.66] group-has-[#tcar-13-5:checked]:z-[3] group-has-[#tcar-13-3:focus-visible]:outline-3 group-has-[#tcar-13-3:focus-visible]:outline-tcar13-acc group-has-[#tcar-13-3:focus-visible]:outline-offset-4 motion-reduce:transition-none">
        <img src="https://picsum.photos/seed/cover-3/500/500" width="500" height="500" decoding="async" alt="Album: Solstice" class="size-full object-cover block pointer-events-none"><label for="tcar-13-3" aria-label="Show cover 3" class="absolute inset-0 cursor-pointer"></label>
      </figure>
      <figure class="absolute top-1/2 left-1/2 size-[220px] -mt-[110px] -ml-[110px] m-0 rounded-[10px] overflow-hidden transform-3d opacity-55 shadow-[0_24px_40px_-20px_oklch(0_0_0/0.8)] transition-[translate,scale,opacity,transform] duration-500 ease-[cubic-bezier(0.2,0.8,0.2,1)] group-has-[#tcar-13-1:checked]:translate-x-[285px] group-has-[#tcar-13-1:checked]:rotate-y-[-52deg] group-has-[#tcar-13-1:checked]:scale-[0.52] group-has-[#tcar-13-1:checked]:opacity-35 group-has-[#tcar-13-1:checked]:z-[2] group-has-[#tcar-13-2:checked]:translate-x-[210px] group-has-[#tcar-13-2:checked]:rotate-y-[-48deg] group-has-[#tcar-13-2:checked]:scale-[0.66] group-has-[#tcar-13-2:checked]:z-[3] group-has-[#tcar-13-3:checked]:translate-x-[120px] group-has-[#tcar-13-3:checked]:rotate-y-[-42deg] group-has-[#tcar-13-3:checked]:scale-[0.82] group-has-[#tcar-13-3:checked]:opacity-75 group-has-[#tcar-13-3:checked]:z-[4] group-has-[#tcar-13-4:checked]:translate-x-0 group-has-[#tcar-13-4:checked]:rotate-y-0 group-has-[#tcar-13-4:checked]:scale-100 group-has-[#tcar-13-4:checked]:opacity-100 group-has-[#tcar-13-4:checked]:z-[5] group-has-[#tcar-13-5:checked]:-translate-x-[120px] group-has-[#tcar-13-5:checked]:rotate-y-[42deg] group-has-[#tcar-13-5:checked]:scale-[0.82] group-has-[#tcar-13-5:checked]:opacity-75 group-has-[#tcar-13-5:checked]:z-[4] group-has-[#tcar-13-4:focus-visible]:outline-3 group-has-[#tcar-13-4:focus-visible]:outline-tcar13-acc group-has-[#tcar-13-4:focus-visible]:outline-offset-4 motion-reduce:transition-none">
        <img src="https://picsum.photos/seed/cover-4/500/500" width="500" height="500" loading="lazy" decoding="async" alt="Album: Undertow" class="size-full object-cover block pointer-events-none"><label for="tcar-13-4" aria-label="Show cover 4" class="absolute inset-0 cursor-pointer"></label>
      </figure>
      <figure class="absolute top-1/2 left-1/2 size-[220px] -mt-[110px] -ml-[110px] m-0 rounded-[10px] overflow-hidden transform-3d opacity-55 shadow-[0_24px_40px_-20px_oklch(0_0_0/0.8)] transition-[translate,scale,opacity,transform] duration-500 ease-[cubic-bezier(0.2,0.8,0.2,1)] group-has-[#tcar-13-1:checked]:translate-x-[345px] group-has-[#tcar-13-1:checked]:rotate-y-[-54deg] group-has-[#tcar-13-1:checked]:scale-[0.42] group-has-[#tcar-13-1:checked]:opacity-20 group-has-[#tcar-13-1:checked]:z-[1] group-has-[#tcar-13-2:checked]:translate-x-[285px] group-has-[#tcar-13-2:checked]:rotate-y-[-52deg] group-has-[#tcar-13-2:checked]:scale-[0.52] group-has-[#tcar-13-2:checked]:opacity-35 group-has-[#tcar-13-2:checked]:z-[2] group-has-[#tcar-13-3:checked]:translate-x-[210px] group-has-[#tcar-13-3:checked]:rotate-y-[-48deg] group-has-[#tcar-13-3:checked]:scale-[0.66] group-has-[#tcar-13-3:checked]:z-[3] group-has-[#tcar-13-4:checked]:translate-x-[120px] group-has-[#tcar-13-4:checked]:rotate-y-[-42deg] group-has-[#tcar-13-4:checked]:scale-[0.82] group-has-[#tcar-13-4:checked]:opacity-75 group-has-[#tcar-13-4:checked]:z-[4] group-has-[#tcar-13-5:checked]:translate-x-0 group-has-[#tcar-13-5:checked]:rotate-y-0 group-has-[#tcar-13-5:checked]:scale-100 group-has-[#tcar-13-5:checked]:opacity-100 group-has-[#tcar-13-5:checked]:z-[5] group-has-[#tcar-13-5:focus-visible]:outline-3 group-has-[#tcar-13-5:focus-visible]:outline-tcar13-acc group-has-[#tcar-13-5:focus-visible]:outline-offset-4 motion-reduce:transition-none">
        <img src="https://picsum.photos/seed/cover-5/500/500" width="500" height="500" loading="lazy" decoding="async" alt="Album: Vantage" class="size-full object-cover block pointer-events-none"><label for="tcar-13-5" aria-label="Show cover 5" class="absolute inset-0 cursor-pointer"></label>
      </figure>
    </div>
  </div>
</section>
@import "tailwindcss";

@theme {
  --color-tcar13-bg: #111018;
  --color-tcar13-bg: oklch(0.18 0.015 290);
  --color-tcar13-acc: #7c5cff;
  --color-tcar13-acc: oklch(0.6 0.2 285);
  --font-tcar13-sans: 'Space Grotesk', system-ui, sans-serif;
}

.tcar-13 {
  width: 100%;
  min-height: 100svh;
}

.tcar-13 ::selection {
  background: var(--color-tcar13-acc);
  color: #fff;
}

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-tcar13-bg: #111018;
  --color-tcar13-bg: oklch(0.18 0.015 290);
  --color-tcar13-acc: #7c5cff;
  --color-tcar13-acc: oklch(0.6 0.2 285);
  --font-tcar13-sans: 'Space Grotesk', system-ui, sans-serif;
}

.tcar-13 {
  width: 100%;
  min-height: 100svh;
}

.tcar-13 ::selection {
  background: var(--color-tcar13-acc);
  color: #fff;
}
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=Space+Grotesk:wght@400;500;600;700&display=swap">

What changed in the port

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

  • Honest assessment: this class list is long, and the CSS version's twenty-five-line selector block is arguably easier to scan as a matrix. What the port buys is locality — a cover's five positions are on the cover — and safety, since adding a sixth cover no longer means renumbering a block of :nth-child selectors.
  • v4's separate translate and scale utilities are what make this possible at all — under the old transform shorthand each condition would have had to restate all three values, as the CSS original does. rotate-y-* is the exception that proves the rule: it still compiles into transform, which is why transform and not rotate belongs in the transition list.
  • UI change from the CSS original: the focus ring moved from the cover's :focus-visible sibling chain onto the same group-has- condition as the transform, so the ring now follows the cover the keyboard selects even mid-transition.
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 Coverflow Carousel with Perspective Transforms
Source: https://codefronts.com/snippets/tailwind-css-image-carousel/tailwind-3d-coverflow-carousel-perspective/

The Cover Flow effect: the centre image faces you full-size while the flanking covers tilt back in 3D. Tailwind v4 added real perspective-*, transform-3d and rotate-y-* utilities, so the 3D is native — but this is also the one demo where the port relocates complexity rather than removing it.
## HTML
```html
<section class="tcar-13 w-full min-h-svh grid place-items-center bg-tcar13-bg font-tcar13-sans px-5 py-10" aria-label="Album coverflow">
  <div class="group w-[min(560px,100%)] perspective-[1200px]">
    <input type="radio" name="tcar-13" id="tcar-13-1" class="sr-only">
    <input type="radio" name="tcar-13" id="tcar-13-2" class="sr-only">
    <input type="radio" name="tcar-13" id="tcar-13-3" class="sr-only" checked>
    <input type="radio" name="tcar-13" id="tcar-13-4" class="sr-only">
    <input type="radio" name="tcar-13" id="tcar-13-5" class="sr-only">
    <div class="relative h-[300px] transform-3d">
      <figure class="absolute top-1/2 left-1/2 size-[220px] -mt-[110px] -ml-[110px] m-0 rounded-[10px] overflow-hidden transform-3d opacity-55 shadow-[0_24px_40px_-20px_oklch(0_0_0/0.8)] transition-[translate,scale,opacity,transform] duration-500 ease-[cubic-bezier(0.2,0.8,0.2,1)] group-has-[#tcar-13-1:checked]:translate-x-0 group-has-[#tcar-13-1:checked]:rotate-y-0 group-has-[#tcar-13-1:checked]:scale-100 group-has-[#tcar-13-1:checked]:opacity-100 group-has-[#tcar-13-1:checked]:z-[5] group-has-[#tcar-13-2:checked]:-translate-x-[120px] group-has-[#tcar-13-2:checked]:rotate-y-[42deg] group-has-[#tcar-13-2:checked]:scale-[0.82] group-has-[#tcar-13-2:checked]:opacity-75 group-has-[#tcar-13-2:checked]:z-[4] group-has-[#tcar-13-3:checked]:-translate-x-[210px] group-has-[#tcar-13-3:checked]:rotate-y-[48deg] group-has-[#tcar-13-3:checked]:scale-[0.66] group-has-[#tcar-13-3:checked]:z-[3] group-has-[#tcar-13-4:checked]:-translate-x-[285px] group-has-[#tcar-13-4:checked]:rotate-y-[52deg] group-has-[#tcar-13-4:checked]:scale-[0.52] group-has-[#tcar-13-4:checked]:opacity-35 group-has-[#tcar-13-4:checked]:z-[2] group-has-[#tcar-13-5:checked]:-translate-x-[345px] group-has-[#tcar-13-5:checked]:rotate-y-[54deg] group-has-[#tcar-13-5:checked]:scale-[0.42] group-has-[#tcar-13-5:checked]:opacity-20 group-has-[#tcar-13-5:checked]:z-[1] group-has-[#tcar-13-1:focus-visible]:outline-3 group-has-[#tcar-13-1:focus-visible]:outline-tcar13-acc group-has-[#tcar-13-1:focus-visible]:outline-offset-4 motion-reduce:transition-none">
        <img src="https://picsum.photos/seed/cover-1/500/500" width="500" height="500" loading="lazy" decoding="async" alt="Album: Nocturne" class="size-full object-cover block pointer-events-none"><label for="tcar-13-1" aria-label="Show cover 1" class="absolute inset-0 cursor-pointer"></label>
      </figure>
      <figure class="absolute top-1/2 left-1/2 size-[220px] -mt-[110px] -ml-[110px] m-0 rounded-[10px] overflow-hidden transform-3d opacity-55 shadow-[0_24px_40px_-20px_oklch(0_0_0/0.8)] transition-[translate,scale,opacity,transform] duration-500 ease-[cubic-bezier(0.2,0.8,0.2,1)] group-has-[#tcar-13-1:checked]:translate-x-[120px] group-has-[#tcar-13-1:checked]:rotate-y-[-42deg] group-has-[#tcar-13-1:checked]:scale-[0.82] group-has-[#tcar-13-1:checked]:opacity-75 group-has-[#tcar-13-1:checked]:z-[4] group-has-[#tcar-13-2:checked]:translate-x-0 group-has-[#tcar-13-2:checked]:rotate-y-0 group-has-[#tcar-13-2:checked]:scale-100 group-has-[#tcar-13-2:checked]:opacity-100 group-has-[#tcar-13-2:checked]:z-[5] group-has-[#tcar-13-3:checked]:-translate-x-[120px] group-has-[#tcar-13-3:checked]:rotate-y-[42deg] group-has-[#tcar-13-3:checked]:scale-[0.82] group-has-[#tcar-13-3:checked]:opacity-75 group-has-[#tcar-13-3:checked]:z-[4] group-has-[#tcar-13-4:checked]:-translate-x-[210px] group-has-[#tcar-13-4:checked]:rotate-y-[48deg] group-has-[#tcar-13-4:checked]:scale-[0.66] group-has-[#tcar-13-4:checked]:z-[3] group-has-[#tcar-13-5:checked]:-translate-x-[285px] group-has-[#tcar-13-5:checked]:rotate-y-[52deg] group-has-[#tcar-13-5:checked]:scale-[0.52] group-has-[#tcar-13-5:checked]:opacity-35 group-has-[#tcar-13-5:checked]:z-[2] group-has-[#tcar-13-2:focus-visible]:outline-3 group-has-[#tcar-13-2:focus-visible]:outline-tcar13-acc group-has-[#tcar-13-2:focus-visible]:outline-offset-4 motion-reduce:transition-none">
        <img src="https://picsum.photos/seed/cover-2/500/500" width="500" height="500" loading="lazy" decoding="async" alt="Album: Parallel" class="size-full object-cover block pointer-events-none"><label for="tcar-13-2" aria-label="Show cover 2" class="absolute inset-0 cursor-pointer"></label>
      </figure>
      <figure class="absolute top-1/2 left-1/2 size-[220px] -mt-[110px] -ml-[110px] m-0 rounded-[10px] overflow-hidden transform-3d opacity-55 shadow-[0_24px_40px_-20px_oklch(0_0_0/0.8)] transition-[translate,scale,opacity,transform] duration-500 ease-[cubic-bezier(0.2,0.8,0.2,1)] group-has-[#tcar-13-1:checked]:translate-x-[210px] group-has-[#tcar-13-1:checked]:rotate-y-[-48deg] group-has-[#tcar-13-1:checked]:scale-[0.66] group-has-[#tcar-13-1:checked]:z-[3] group-has-[#tcar-13-2:checked]:translate-x-[120px] group-has-[#tcar-13-2:checked]:rotate-y-[-42deg] group-has-[#tcar-13-2:checked]:scale-[0.82] group-has-[#tcar-13-2:checked]:opacity-75 group-has-[#tcar-13-2:checked]:z-[4] group-has-[#tcar-13-3:checked]:translate-x-0 group-has-[#tcar-13-3:checked]:rotate-y-0 group-has-[#tcar-13-3:checked]:scale-100 group-has-[#tcar-13-3:checked]:opacity-100 group-has-[#tcar-13-3:checked]:z-[5] group-has-[#tcar-13-4:checked]:-translate-x-[120px] group-has-[#tcar-13-4:checked]:rotate-y-[42deg] group-has-[#tcar-13-4:checked]:scale-[0.82] group-has-[#tcar-13-4:checked]:opacity-75 group-has-[#tcar-13-4:checked]:z-[4] group-has-[#tcar-13-5:checked]:-translate-x-[210px] group-has-[#tcar-13-5:checked]:rotate-y-[48deg] group-has-[#tcar-13-5:checked]:scale-[0.66] group-has-[#tcar-13-5:checked]:z-[3] group-has-[#tcar-13-3:focus-visible]:outline-3 group-has-[#tcar-13-3:focus-visible]:outline-tcar13-acc group-has-[#tcar-13-3:focus-visible]:outline-offset-4 motion-reduce:transition-none">
        <img src="https://picsum.photos/seed/cover-3/500/500" width="500" height="500" decoding="async" alt="Album: Solstice" class="size-full object-cover block pointer-events-none"><label for="tcar-13-3" aria-label="Show cover 3" class="absolute inset-0 cursor-pointer"></label>
      </figure>
      <figure class="absolute top-1/2 left-1/2 size-[220px] -mt-[110px] -ml-[110px] m-0 rounded-[10px] overflow-hidden transform-3d opacity-55 shadow-[0_24px_40px_-20px_oklch(0_0_0/0.8)] transition-[translate,scale,opacity,transform] duration-500 ease-[cubic-bezier(0.2,0.8,0.2,1)] group-has-[#tcar-13-1:checked]:translate-x-[285px] group-has-[#tcar-13-1:checked]:rotate-y-[-52deg] group-has-[#tcar-13-1:checked]:scale-[0.52] group-has-[#tcar-13-1:checked]:opacity-35 group-has-[#tcar-13-1:checked]:z-[2] group-has-[#tcar-13-2:checked]:translate-x-[210px] group-has-[#tcar-13-2:checked]:rotate-y-[-48deg] group-has-[#tcar-13-2:checked]:scale-[0.66] group-has-[#tcar-13-2:checked]:z-[3] group-has-[#tcar-13-3:checked]:translate-x-[120px] group-has-[#tcar-13-3:checked]:rotate-y-[-42deg] group-has-[#tcar-13-3:checked]:scale-[0.82] group-has-[#tcar-13-3:checked]:opacity-75 group-has-[#tcar-13-3:checked]:z-[4] group-has-[#tcar-13-4:checked]:translate-x-0 group-has-[#tcar-13-4:checked]:rotate-y-0 group-has-[#tcar-13-4:checked]:scale-100 group-has-[#tcar-13-4:checked]:opacity-100 group-has-[#tcar-13-4:checked]:z-[5] group-has-[#tcar-13-5:checked]:-translate-x-[120px] group-has-[#tcar-13-5:checked]:rotate-y-[42deg] group-has-[#tcar-13-5:checked]:scale-[0.82] group-has-[#tcar-13-5:checked]:opacity-75 group-has-[#tcar-13-5:checked]:z-[4] group-has-[#tcar-13-4:focus-visible]:outline-3 group-has-[#tcar-13-4:focus-visible]:outline-tcar13-acc group-has-[#tcar-13-4:focus-visible]:outline-offset-4 motion-reduce:transition-none">
        <img src="https://picsum.photos/seed/cover-4/500/500" width="500" height="500" loading="lazy" decoding="async" alt="Album: Undertow" class="size-full object-cover block pointer-events-none"><label for="tcar-13-4" aria-label="Show cover 4" class="absolute inset-0 cursor-pointer"></label>
      </figure>
      <figure class="absolute top-1/2 left-1/2 size-[220px] -mt-[110px] -ml-[110px] m-0 rounded-[10px] overflow-hidden transform-3d opacity-55 shadow-[0_24px_40px_-20px_oklch(0_0_0/0.8)] transition-[translate,scale,opacity,transform] duration-500 ease-[cubic-bezier(0.2,0.8,0.2,1)] group-has-[#tcar-13-1:checked]:translate-x-[345px] group-has-[#tcar-13-1:checked]:rotate-y-[-54deg] group-has-[#tcar-13-1:checked]:scale-[0.42] group-has-[#tcar-13-1:checked]:opacity-20 group-has-[#tcar-13-1:checked]:z-[1] group-has-[#tcar-13-2:checked]:translate-x-[285px] group-has-[#tcar-13-2:checked]:rotate-y-[-52deg] group-has-[#tcar-13-2:checked]:scale-[0.52] group-has-[#tcar-13-2:checked]:opacity-35 group-has-[#tcar-13-2:checked]:z-[2] group-has-[#tcar-13-3:checked]:translate-x-[210px] group-has-[#tcar-13-3:checked]:rotate-y-[-48deg] group-has-[#tcar-13-3:checked]:scale-[0.66] group-has-[#tcar-13-3:checked]:z-[3] group-has-[#tcar-13-4:checked]:translate-x-[120px] group-has-[#tcar-13-4:checked]:rotate-y-[-42deg] group-has-[#tcar-13-4:checked]:scale-[0.82] group-has-[#tcar-13-4:checked]:opacity-75 group-has-[#tcar-13-4:checked]:z-[4] group-has-[#tcar-13-5:checked]:translate-x-0 group-has-[#tcar-13-5:checked]:rotate-y-0 group-has-[#tcar-13-5:checked]:scale-100 group-has-[#tcar-13-5:checked]:opacity-100 group-has-[#tcar-13-5:checked]:z-[5] group-has-[#tcar-13-5:focus-visible]:outline-3 group-has-[#tcar-13-5:focus-visible]:outline-tcar13-acc group-has-[#tcar-13-5:focus-visible]:outline-offset-4 motion-reduce:transition-none">
        <img src="https://picsum.photos/seed/cover-5/500/500" width="500" height="500" loading="lazy" decoding="async" alt="Album: Vantage" class="size-full object-cover block pointer-events-none"><label for="tcar-13-5" aria-label="Show cover 5" class="absolute inset-0 cursor-pointer"></label>
      </figure>
    </div>
  </div>
</section>
```
## CSS
```css
@import "tailwindcss";

@theme {
  --color-tcar13-bg: #111018;
  --color-tcar13-bg: oklch(0.18 0.015 290);
  --color-tcar13-acc: #7c5cff;
  --color-tcar13-acc: oklch(0.6 0.2 285);
  --font-tcar13-sans: 'Space Grotesk', system-ui, sans-serif;
}

.tcar-13 {
  width: 100%;
  min-height: 100svh;
}

.tcar-13 ::selection {
  background: var(--color-tcar13-acc);
  color: #fff;
}
```

How this works

3D is a first-class utility now. perspective-[1200px], transform-3d and rotate-y-[-42deg] replace the three properties this effect has always needed, and translate-x / scale compose alongside them without clobbering each other.

But rotate-y-* is not the rotate property. It sets --tw-rotate-y and composes into transform, so the transition list must name transform: transition-[translate,scale,opacity,transform]. Write transition-[...,rotate] instead and the tilt snaps while everything else eases — the single easiest mistake to make with v4's 3D utilities.

This port relocates, it does not shrink. Coverflow genuinely has twenty-five states; there is no clever variant that collapses them. What changes is where they live: each cover's five positions sit on that cover, so reading one cover tells you its whole life, and adding a sixth means editing six elements instead of renumbering a twenty-five-line selector block.

Depth needs z-index per tier. Every condition sets a z-[N], because 3D transforms do not by themselves guarantee paint order in a preserve-3d context across browsers.

Make it yours

  • Spread and depth: the translate-x / rotate-y / scale triples per tier.
  • Stage depth: perspective-[1200px] — smaller is more dramatic.
  • Accent ring: --color-tcar13-acc.
  • Reflections: add an after: mirrored layer under each cover.

Gotchas — read before shipping

  • Without transform-3d on the deck, rotate-y renders as a flat horizontal squash — the classic symptom of a missing preserve-3d.
  • Every tier needs an explicit z-*, or the centre cover can paint under a neighbour.
  • The <label> hit areas must sit above the images; the images carry pointer-events-none so a click always reaches the label.

Browser support

ChromeSafariFirefoxEdge
111+16.4+128+111+

3D transforms are universal; Tailwind v4's perspective-*, transform-3d and rotate-y-* utilities require v4.0+, and :has() drives the state map.

Techniques used in this demo

Search CodeFronts

Loading…