Flip Card

The card turns over in 3D to reveal details on its back, and turns back on the next click.

  • CSS
  • Cards
  • Click
  • Added

AI prompt

Build a React flip card in CSS 3D. The card is a <button> with aria-pressed so it works with keyboard and screen readers. Inside, an inner element has transform-style: preserve-3d and a 600ms transition on transform with cubic-bezier(0.65, 0, 0.35, 1); when pressed it rotates rotateY(180deg). The front and back faces are stacked with position absolute, backface-visibility: hidden, and the back face is pre-rotated rotateY(180deg). Add perspective: 900px on the button. Front shows "Kopi O" with "Tap to reveal"; back shows "Black coffee with sugar. Strong, sweet, no milk." and "Tap again to flip back". Hide the face that is turned away from screen readers with aria-hidden. Under prefers-reduced-motion, crossfade the faces over 150ms instead of rotating.

Source

Demo.tsx
'use client'

import { useState } from 'react'
import s from './demo.module.css'

export default function FlipCard({ labels }: { labels: Record<string, string> }) {
  const [flipped, setFlipped] = useState(false)

  return (
    <button type="button" className={s.card} aria-pressed={flipped} onClick={() => setFlipped(!flipped)}>
      <span className={s.inner}>
        <span className={`${s.face} ${s.front}`} aria-hidden={flipped}>
          <strong className={s.title}>{labels.title}</strong>
          <span className={s.hint}>{labels.front}</span>
        </span>
        <span className={`${s.face} ${s.back}`} aria-hidden={!flipped}>
          <span className={s.text}>{labels.back}</span>
          <span className={s.hint}>{labels.hint}</span>
        </span>
      </span>
    </button>
  )
}
demo.module.css
.card {
  width: 200px;
  height: 180px;
  padding: 0;
  border: 0;
  background: none;
  perspective: 900px;
  cursor: pointer;
}

.card:focus-visible { outline: 2px solid var(--color-focus); outline-offset: 4px; border-radius: 16px; }

.inner {
  position: relative;
  display: block;
  width: 100%;
  height: 100%;
  transform-style: preserve-3d;
  transition: transform 600ms var(--ease-in-out);
}

.card[aria-pressed='true'] .inner { transform: rotateY(180deg); }

.face {
  position: absolute;
  inset: 0;
  display: grid;
  align-content: space-between;
  padding: 18px;
  border-radius: 16px;
  text-align: left;
  backface-visibility: hidden;
}

.front { background: var(--stage-accent); color: var(--stage-accent-ink); }
.back { background: var(--stage-surface); border: 1px solid var(--stage-rule); color: var(--stage-ink); transform: rotateY(180deg); }

.title { font: 700 var(--text-2xl) / 1.1 var(--font-display); }
.text { font: 400 var(--text-sm) / 1.5 var(--font-body); }
.hint { font: 500 var(--text-xs) / 1.2 var(--font-mono); letter-spacing: 0.04em; opacity: 0.75; }

@media (prefers-reduced-motion: reduce) {
  .inner { transition: none; }
  .card[aria-pressed='true'] .inner { transform: none; }
  .face { transition: opacity 150ms linear; transform: none; }
  .card[aria-pressed='true'] .front, .card[aria-pressed='false'] .back { opacity: 0; }
}

Suggest an idea

Seen a motion or a theme you would like to find here? Describe it, and it opens as a prefilled GitHub issue for you to post.

What are you suggesting?

Needs a GitHub account. Suggestions are public.