Tilt card

Free · MIT

Tilts toward the pointer on a spring with a moving glare, a shifting shadow and layers that float at their own depth.

MarkdownOpen in v0
Open in v0

Installation

$ npx shadcn@latest add https://goodui.dev/r/tilt-card.json

The file lands in components/goodui/tilt-card.tsx and is yours to edit. With the @goodui registry added, npx shadcn@latest add @goodui/tilt-card works too.

Usage

import { TiltCard, TiltCardLayer } from "@/components/goodui/tilt-card"

export function MembershipCard() {
  return (
    <TiltCard className="w-80 bg-gradient-to-br from-violet-600 to-indigo-700 p-6 text-white">
      <TiltCardLayer depth={20}>
        <p className="text-xs tracking-widest text-white/70 uppercase">Glow Studio</p>
      </TiltCardLayer>
      <TiltCardLayer depth={50} className="mt-10">
        <p className="text-2xl font-semibold">Gold membership</p>
        <p className="text-sm text-white/80">Unlimited blow-dries · 10% off color</p>
      </TiltCardLayer>
      <TiltCardLayer depth={30} className="mt-8 flex items-end justify-between">
        <span className="text-sm">Maya Chen</span>
        <span className="font-mono text-sm">$89/mo</span>
      </TiltCardLayer>
    </TiltCard>
  )
}

When to use

Use it for
  • Showcase cards on a landing page: a pricing plan, a product shot, a gift card or membership card.
  • Cards with layered content (badge, avatar, price) that should float at different depths with TiltCardLayer.
  • Portfolio and template galleries, where a tactile hover invites a click.
Reach for something else
  • A card that only needs a simple tilt plus variants, tones and header/footer parts: card with animation="tilt" is simpler. Use TiltCard for springs, glare control and depth layers.
  • Data-heavy cards (tables, charts, forms): tilting makes text harder to read and click. Use card with animation="lift".
  • Large grids of many cards: one tilting card draws the eye, twenty feel restless. Use spotlight-card with SpotlightGroup.
If you needUse
Subtle, app-friendly tiltmaxTilt={6} scale={1.01}
Dramatic showcasemaxTilt={15} perspective={600}
No glareglare={false}
Floating badge or image<TiltCardLayer depth={40}>…</TiltCardLayer>
Turn it off conditionallydisabled

Examples

Calm pricing card

<TiltCard maxTilt={6} scale={1.01} glareOpacity={0.2} className="p-6" containerClassName="h-full">
  <h3 className="font-semibold">Team</h3>
  <p className="mt-2 text-3xl font-bold">$49<span className="text-base font-normal text-muted-foreground">/mo</span></p>
</TiltCard>

API reference

TiltCard

PropTypeDefault
maxTilt
Maximum tilt in degrees.
number10
scale
Scale while hovered.
number1.02
glare
Show a light glare that follows the pointer.
booleantrue
glareOpacity
Peak opacity of the glare.
number0.35
perspective
CSS perspective in px; lower is more dramatic.
number900
disabled
Keep the card flat (no tilt, glare or scale).
booleanfalse
containerClassName
Classes for the outer element that holds the perspective and receives the pointer.
string—

Also accepts every <div> attribute.

TiltCardLayer

PropTypeDefault
depth
How far the layer floats above the card, in px.
number30

Also accepts every <div> attribute.

Accessibility

  • TiltCard renders two plain <div>s (a perspective container and the card); it adds no roles. Put real links or buttons inside for interaction.
  • The glare layer is aria-hidden and ignores the pointer.
  • Touch, keyboard and reduced-motion users get a flat card with the same content.

Motion

  • The card rotates toward the pointer by up to `maxTilt` degrees (10) and scales to `scale` (1.02), on a spring (stiffness 220, damping 22, mass 0.6).
  • A radial glare follows the pointer at up to `glareOpacity` (0.35), and the shadow shifts against the tilt and fades in on hover (spring, stiffness 200, damping 26).
  • TiltCardLayer children float `depth` px (30) above the card with translateZ, so they move with parallax.
  • Leaving the card springs it back flat. Touch input is ignored.
  • Reduced motion or disabled: no tilt, scale, glare or shadow shift; the card stays flat.
  • Pointer moves only set motion values, so React does not re-render. Effects use transform, opacity and box-shadow.

Notes for AI

Coding agents read these rules through MCP and llms.txt, or paste this page with Copy page.

  • className styles the card (padding, background); containerClassName styles the outer element that holds the perspective and receives the pointer (sizing in grids, e.g. h-full).
  • TiltCardLayer only floats when every element between it and the card keeps transform-style: preserve-3d and has no overflow: hidden.
  • maxTilt is degrees, perspective and depth are px, scale is a factor (1.02 means 2% larger).
  • The card already has rounded-xl, border, bg-card; override with className.

FAQ

Why is my layer not floating?

Some element between the layer and the card flattens 3D: overflow: hidden, or a wrapper without transform-style: preserve-3d. Make TiltCardLayer a direct child of TiltCard, or nest layers inside layers.

Core card animation="tilt" or TiltCard?

The Core card's tilt is a CSS transition with a light sheen and works with all card variants. TiltCard adds springs, a glare you can tune, a moving shadow and parallax layers.

Related