WebberUI

Flip Reveal Card

A 3D flip card that rotates around the X or Y axis to reveal its front and back, supporting hover, click, and fully controlled use.

Loading preview…
npx shadcn@latest add https://webberui.com/r/flip-reveal-card.json

Playground

Tune the props live — the code snippet updates as you go, so you can dial in the look you want before copying it.

1000
0.6
<FlipRevealCard />

Installation

npx shadcn@latest add https://webberui.com/r/flip-reveal-card.json

Or, once registries are configured in components.json, install it as @webberui/flip-reveal-card.

Usage

import {
  FlipRevealCard,
  FlipRevealFront,
  FlipRevealBack,
} from "@/components/ui/flip-reveal-card";

<FlipRevealCard trigger="hover" axis="y" className="h-40 w-64">
  <FlipRevealFront>
    <h3 className="text-base font-semibold">Front</h3>
  </FlipRevealFront>
  <FlipRevealBack>
    <p className="text-sm">Back-side content, only visible once you flip it over.</p>
  </FlipRevealBack>
</FlipRevealCard>

The two faces stack automatically in the same grid cell and the card takes the height of the taller one; you can also set a fixed height directly on FlipRevealCard through className (for example h-40).

Controlled mode

Passing flipped switches to controlled mode, and combining it with trigger="none" puts the flip entirely under external control:

const [flipped, setFlipped] = React.useState(false);

<>
  <FlipRevealCard trigger="none" flipped={flipped} className="h-40 w-64">
    <FlipRevealFront>Front</FlipRevealFront>
    <FlipRevealBack>Back</FlipRevealBack>
  </FlipRevealCard>
  <button onClick={() => setFlipped((v) => !v)}>Flip</button>
</>

Props

FlipRevealCard

PropTypeDefaultDescription
childrenReact.ReactNodePut FlipRevealFront and FlipRevealBack here
trigger"hover" | "click" | "none""hover"How it is triggered: hover / focus, click to toggle, or fully controlled
axis"x" | "y""y"Flip axis: y flips left-to-right, x flips top-to-bottom
flippedbooleanControlled state; supplying it disables the internal state
defaultFlippedbooleanfalseInitial flipped state in uncontrolled mode
onFlippedChange(flipped: boolean) => voidFires when the flipped state changes
perspectivenumber10003D perspective distance (px); smaller values make the depth more pronounced
durationnumber0.6Duration of the flip animation (seconds)
classNamestringAppended to the outermost container (commonly used to set width and height)

The remaining standard div attributes (such as aria-label) are supported as well.

FlipRevealFront / FlipRevealBack

PropTypeDefaultDescription
childrenReact.ReactNodeContent of that face
classNamestringOverride the default face appearance (border, background, padding, and so on)

Both inherit the standard div attributes.

How it works

  • The two faces stack in the same CSS Grid cell and use backface-visibility: hidden to hide whichever one is turned away from the viewer; the rotating container carries transform-style: preserve-3d, so never add overflow-hidden to it (that flattens the 3D context).
  • The faces themselves are free to set overflow-hidden and rounded corners, because they are only flat content layers.
  • When axis changes, the back face automatically switches to a 180° pre-rotation on the matching axis, so the front and back always stay coplanar and aligned.

Accessibility

  • When the user has "reduce motion" enabled at the system level, the flip becomes an instant switch (duration 0) with no rotation animation and no change to the DOM structure.
  • Whichever face is currently turned away is marked aria-hidden and given inert, so a screen reader will not announce it and focusable elements inside it stay out of the tab order.
  • With trigger="click", the container is role="button" and focusable, supports Enter / Space to toggle, and aria-pressed reflects the current face.
  • With trigger="hover", the container is focusable and keyboard focus flips it (equivalent to hovering), flipping back on blur; giving the card a name through aria-label is recommended.

On this page