Tilt Card <mv-tilt>
Inclinación 3D sutil bajo un puntero preciso, con un brillo suave y parallax data-depth, plana y nítida en reposo, una ligera elevación con el foco del teclado y sin inclinación en pantallas táctiles ni con movimiento reducido.
| Categoría | Efectos |
|---|---|
| Tipo | Web Component (<mv-tilt>) |
| Estado | estable |
| Keywords | tilt, 3d, parallax, glare, perspective, hover, card |
When to use
- A product shot, member card or feature card should turn slightly in 3D under the mouse with a soft glare
- Layered artwork needs a little parallax depth between foreground and background layers on hover
- A clickable card should keep its links and buttons easy to hit while it reacts to the pointer
Avoid when
- The card must reveal a second face with more information → use Flip Card instead
- A cursor-driven light across a grid is wanted without moving the cards → use Spotlight Card instead
Instalación
node scripts/add.mjs tilt-card --out ./src/marvelousAgente de IA con el servidor MCP de Marvelous UI: install_components({ slugs: ["tilt-card"], target_dir: "<absolute path>/src/marvelous", framework: "react" }).
Archivos copiados (dependencias incluidas): tokens/tokens.css, core/base.css, core/dom.js, core/element.js, core/motion.js, components/tilt-card/tilt-card.js, components/tilt-card/tilt-card.css.
Uso
Inicio rápido, el marcado mínimo que funciona:
<mv-tilt glare><article class="mv-card">…</article></mv-tilt>Marcado de referencia: parte de él y personalízalo con atributos, data-* y variables CSS:
<div style="display:flex;flex-wrap:wrap;gap:2.5rem;justify-content:center;align-items:center;width:100%">
<mv-tilt glare style="width:18rem">
<article class="mv-card" data-variant="elevated">
<figure class="mv-card-media" style="position:relative;--mv-card-media-ratio:4/3;background:linear-gradient(140deg,oklch(0.64 0.17 250),oklch(0.56 0.2 290) 55%,oklch(0.72 0.15 20))">
<svg data-depth="40" viewBox="0 0 120 120" aria-hidden="true" style="position:absolute;inset:18% 26%;width:48%;height:auto;filter:drop-shadow(0 10px 16px rgb(0 0 0 / .3))"><circle cx="60" cy="60" r="44" fill="none" stroke="white" stroke-width="7" opacity=".92"/><path d="M60 30v30l20 12" fill="none" stroke="white" stroke-width="7" stroke-linecap="round"/></svg>
<span data-depth="60" style="position:absolute;top:.75rem;right:.75rem;padding:.2rem .6rem;border-radius:var(--mv-radius-full);background:oklch(1 0 0 / .92);color:oklch(0.28 0.06 270);font-size:.75rem;font-weight:600">New</span>
</figure>
<header class="mv-card-header">
<h3 class="mv-card-title">Horizon S2 Watch</h3>
<p class="mv-card-description">Titanium case, 7-day battery life, dual-frequency GPS.</p>
</header>
<footer class="mv-card-footer" style="justify-content:space-between;padding-top:1rem">
<strong style="font-size:1.1rem">$349</strong>
<button class="mv-button" data-size="sm">Add to cart</button>
</footer>
</article>
</mv-tilt>
<mv-tilt max="12" glare style="width:20rem">
<a href="#membership" aria-label="Nebula member card, view membership" style="position:relative;display:flex;flex-direction:column;justify-content:space-between;aspect-ratio:1.586;padding:1.25rem;border-radius:var(--mv-radius-xl);overflow:hidden;color:white;text-decoration:none;background:radial-gradient(120% 90% at 0% 0%,oklch(0.46 0.16 265),transparent 60%),radial-gradient(100% 80% at 100% 100%,oklch(0.52 0.16 195),transparent 60%),oklch(0.21 0.03 265);box-shadow:var(--mv-shadow-lg)">
<span style="display:flex;justify-content:space-between;align-items:flex-start">
<span data-depth="30" style="font-weight:700;letter-spacing:-.02em;font-size:1.1rem">Nebula</span>
<span data-depth="30" style="font-size:.7rem;letter-spacing:.12em;text-transform:uppercase;opacity:.78">Member card</span>
</span>
<span data-depth="20" aria-hidden="true" style="width:2.6rem;height:2rem;border-radius:.4rem;background:linear-gradient(135deg,oklch(0.88 0.1 85),oklch(0.72 0.12 70))"></span>
<span data-depth="45" style="display:block">
<span style="display:block;font-family:var(--mv-font-mono);font-size:1.05rem;letter-spacing:.14em">4970 •••• •••• 2048</span>
<span style="display:flex;justify-content:space-between;margin-top:.4rem;font-size:.75rem;opacity:.82"><span>AVA THOMPSON</span><span>09/29</span></span>
</span>
</a>
</mv-tilt>
</div>API
Attributes
| Name | Tipo | Default | Description |
|---|---|---|---|
max | number | 8 | Maximum angle (degrees). |
scale | number | 1.02 | Scale while hovered. |
perspective | number | 1000 | Perspective (px); smaller = more dramatic. |
glare | boolean | Adds the glare layer (.mv-tilt-glare). | |
reverse | boolean | The edge under the pointer rises instead of sinking. | |
gyroscope | boolean | false | Follows the device orientation on devices without a fine hovering pointer (no permission prompt). |
stiffness / damping | number | 180 / 20 | Spring settings. |
disabled | boolean | Returns the card to flat and stops reacting. |
Content structure
| Name | Description |
|---|---|
first child | The tilted surface (a .mv-card, a link, an image…); receives .mv-tilt-surface. |
[data-depth] | Descendants that ride above the surface and shift with the turn, proportionally to the value (e.g. 20 to 60). |
CSS classes
| Name | Description |
|---|---|
mv-tilt-surface | Added to the first child. No transform at rest. |
mv-tilt-glare | Glare layer injected by the glare attribute (aria-hidden, ignores the pointer). |
CSS variables
| Name | Default | Description |
|---|---|---|
--mv-tilt-rx / --mv-tilt-ry | Current rotation (degrees, unitless), set while active. | |
--mv-tilt-x / --mv-tilt-y | Smoothed pointer, -1 to 1, set while active. | |
--mv-tilt-h | Smoothed hover amount, 0 to 1, set while active. | |
--mv-tilt-glare-color | white 70% | Glare color. |
--mv-tilt-glare-opacity | 0.8 | Glare intensity. |
--mv-tilt-glare-blend | overlay | Glare blend mode. |
Accessibility
Purely visual: the content, its links and buttons stay in the normal tab order and keep their own focus ring. Pointer tilt only runs under (hover: hover) and (pointer: fine); touch and coarse pointers never tilt. Aiming at a link or button inside the card freezes the tilt so the target does not move under the cursor (a card that is itself a link still tilts). Keyboard focus inside the card gives a gentle static lift and shadow, no rotation. Reduced motion: no tilt, scale, parallax or lift; hover only shows a still glare. Forced colors: the glare is hidden. At rest the surface carries no transform, so text stays crisp; the animation loop runs only while the card moves and pauses off screen.