Free Component

3D Tilt Card

A card that tilts in 3D towards the cursor, with its content floating above the surface and a light reflection following the mouse. About 20 lines of JavaScript.

  • dark
  • card
  • 3d
  • interactive
  • javascript
  • hover

The code

Plain HTML, CSS and JavaScript with no dependencies. Copy a single file, or choose "Full file" for a complete page you can save as index.html and open in a browser.

<div class="tilt" id="tilt">
  <div class="tilt-inner">
    <span class="chip">Featured</span>
    <h3>3D Tilt Card</h3>
    <p>Move your cursor over me.</p>
  </div>
</div>

The AI prompt

Paste this into an AI coding tool to generate the same component, then ask it to adapt the colours, text or framework to your project.

Works with Claude · ChatGPT · Cursor · v0 · Bolt · Gemini
Create an interactive 3D tilt card with HTML, CSS and vanilla JavaScript (no libraries).

Card:
- Width min(86vw, 340px), aspect-ratio 4/5, 24px radius, navy-to-indigo gradient background, large dark shadow, centred on a dark page.
- transform-style: preserve-3d on the card; an inner content layer positioned absolutely with transform: translateZ(50px) so it floats above the card when tilted.
- Content: an orange "Featured" chip at the top, heading "3D Tilt Card" and a line of text at the bottom.
- A ::after overlay with a radial-gradient highlight positioned at CSS variables --mx and --my; opacity 0 by default, 1 on hover.

JavaScript:
- On pointermove, compute the pointer position within the card as fractions px and py (0 to 1).
- rotateY = (px - 0.5) * 2 * 14 and rotateX = (0.5 - py) * 2 * 14 (max 14 degrees).
- Set transform to "perspective(900px) rotateX(...) rotateY(...) scale(1.03)" with a quick 0.1s transition, and update --mx / --my as percentages.
- On pointerleave, reset the transform with a slower 0.5s transition.

Return a single HTML file with <style> and <script> tags.

How to build it, step by step

  1. 1

    Work out where the pointer is inside the card as a fraction from 0 to 1 on each axis using getBoundingClientRect.

  2. 2

    Convert that to rotation: the further from the centre, the larger the angle. Horizontal movement drives rotateY, vertical movement drives rotateX (inverted).

  3. 3

    Apply perspective() inside the transform. Without perspective, 3D rotations look flat.

  4. 4

    Add transform-style: preserve-3d to the card and translateZ() to the inner content so it separates from the surface when tilted.

  5. 5

    Feed the same pointer position into CSS variables to move a radial-gradient highlight.

  6. 6

    On pointerleave, clear the transform with a longer transition so the card settles back smoothly.

Customisation tips

  • Lower MAX to 6-8 degrees for large cards; big cards need less tilt to feel right.
  • Skip the effect on touch devices by checking window.matchMedia('(hover: hover)').
  • Give different children different translateZ values (30px, 50px, 70px) for a layered parallax effect.

More components