Mantine Parallax

Logo

@gfazioli/mantine-parallax

A Mantine component that allows you to create the famous Apple TV parallax effect.

Installation

yarn add @gfazioli/mantine-parallax

After installation import package styles at the root of your application:

import '@gfazioli/mantine-parallax/styles.css';

You can import styles within a layer @layer mantine-parallax by importing @gfazioli/mantine-parallax/styles.layer.css file.

import '@gfazioli/mantine-parallax/styles.layer.css';

Usage

Despite the Parallax component allowing you to create the famous Apple TV Card effect, you can use this component to manipulate the perspective and rotation of an element. It is also possible to act on the skew of the element and disable the parallax effect when hovering with the mouse. See Initial values and Skew below.

The disabled prop allows you to disable the effect. Both perspective and initialPerspective props will be disabled if the value is greater or equal to 10000.

The component supports touch interactions on mobile devices out of the box. You can disable touch support by setting touchEnabled={false}.

The component automatically respects the prefers-reduced-motion media query. When the user has enabled reduced motion in their OS settings, all animations and hover/touch effects are disabled.

You can customize the transition behavior with transitionDuration (in milliseconds, default 300) and transitionEasing (default 'ease-out'). The hoverScale prop (default 1) applies a scale transform when hovering — try values like 1.05 for a subtle zoom effect.

The onRotationChange callback fires whenever the rotation changes, receiving { rotateX, rotateY, isHovering }. Use it to synchronize external effects (shadows, text, other components) with the parallax rotation.

Set resetOnLeave={false} to keep the last rotation position when the mouse leaves instead of resetting to the initial values. The invertRotation prop reverses the tilt direction — the card tilts away from the cursor instead of toward it. Use maxRotation to clamp the rotation to a maximum degree value, useful for achieving subtle effects with high threshold values.

Enable gyroscopeEnabled to use the DeviceOrientation API on mobile devices — the card will tilt based on physical device orientation. On iOS 13+, permission is automatically requested on the first tap. Adjust gyroscopeSensitivity (default 1) to control how much device tilt translates into card rotation.

Keyboard Interaction

Set keyboardEnabled to enable keyboard-driven tilt. When focused (via Tab), use arrow keys to tilt the card and Escape to reset. The component automatically adds tabIndex, focus styles, and ARIA attributes (role="group", aria-roledescription="parallax card"). Adjust keyboardStep (default 5) to control degrees per keypress. Works with springEffect for bouncy keyboard-driven movement.

Norway

Norway Fjord Adventures

On Sale

With Fjord Tours you can explore more of the magical fjord landscapes with tours and activities on and around the fjords of Norway

Max rotation
Gyroscope sensitivity
Keyboard step
Perspective
Initial perspective
Initial rotation x
Initial rotation y
Initial rotation z
Initial skew x
Initial skew y
Hover scale
Threshold
Transition duration
Light intensity
Light size
Light color
Light gradient type
Light gradient angle
import { Parallax } from '@gfazioli/mantine-parallax';

function Demo() {
  return (
    <Center w="100%" h={500}>
      <Parallax  lightEffect lightOverlay lightIntensity={0.1} lightColor="rgba(255, 255, 255, .5)" w={400} radius="md">
        <Card shadow="sm" padding="lg" radius="md" withBorder>
          <Card.Section>
            <Image
              src="https://raw.githubusercontent.com/mantinedev/mantine/master/.demo/images/bg-8.png"
              height={160}
              alt="Norway"
            />
          </Card.Section>

          <Group justify="space-between" mt="md" mb="xs">
            <Text fw={500}>Norway Fjord Adventures</Text>
            <Badge color="pink">On Sale</Badge>
          </Group>

          <Text size="sm" c="dimmed">
            With Fjord Tours you can explore more of the magical fjord
            landscapes with tours and activities on and around the fjords of
            Norway
          </Text>

          <Button color="blue" fullWidth mt="md" radius="md">
            Book classic tour now
          </Button>
        </Card>
      </Parallax>
    </Center>
  );
}

Initial values and Skew

You can set the initial rotation of the card using the initialPerspective, initialRotationX, initialRotationY, and initialRotationZ props. You may also use the initialSkewX and initialSkewY props to set the initial skew of the card.

Norway

Norway Fjord Adventures

On Sale

With Fjord Tours you can explore more of the magical fjord landscapes with tours and activities on and around the fjords of Norway

Perspective
Initial perspective
Initial rotation x
Initial rotation y
Initial rotation z
Initial skew x
Initial skew y
Threshold
Hover scale
Transition duration
Light intensity
Light size
Light color
Light gradient type
Light gradient angle
import { Parallax } from '@gfazioli/mantine-parallax';

function Demo() {
  return (
    <Center w="100%" h={500}>
      <Parallax  initialPerspective={10000} initialRotationX={60} initialSkewX={-30} initialSkewY={30} lightEffect lightOverlay lightIntensity={0.1} lightColor="rgba(255, 255, 255, .5)" w={400}>
        <Card shadow="sm" padding="lg" radius="md" withBorder>
          <Card.Section>
            <Image
              src="https://raw.githubusercontent.com/mantinedev/mantine/master/.demo/images/bg-8.png"
              height={160}
              alt="Norway"
            />
          </Card.Section>

          <Group justify="space-between" mt="md" mb="xs">
            <Text fw={500}>Norway Fjord Adventures</Text>
            <Badge color="pink">On Sale</Badge>
          </Group>

          <Text size="sm" c="dimmed">
            With Fjord Tours you can explore more of the magical fjord
            landscapes with tours and activities on and around the fjords of
            Norway
          </Text>

          <Button color="blue" fullWidth mt="md" radius="md">
            Book classic tour now
          </Button>
        </Card>
      </Parallax>
    </Center>
  );
}

Scroll

The initial values of the Parallax component can be set based on the scroll position. You can use the useWindowScroll() hook to get the scroll position and pass it to the Parallax component.

Norway

Norway Fjord Adventures

On Sale

With Fjord Tours you can explore more of the magical fjord landscapes with tours and activities on and around the fjords of Norway

import { Parallax } from '@gfazioli/mantine-parallax';
import { useWindowScroll } from "@mantine/hooks";

function Demo() {
  const [scroll] = useWindowScroll();

  return (
    <Center w="100%" h={500}>
      <Parallax initialRotationX={(scroll.y - 4400) / 10} w={400}>
        <Card shadow="sm" padding="lg" radius="md" withBorder>
          <Card.Section>
            <Image
              src="https://raw.githubusercontent.com/mantinedev/mantine/master/.demo/images/bg-8.png"
              height={160}
              alt="Norway"
            />
          </Card.Section>

          <Group justify="space-between" mt="md" mb="xs">
            <Text fw={500}>Norway Fjord Adventures</Text>
            <Badge color="pink">On Sale</Badge>
          </Group>

          <Text size="sm" c="dimmed">
            With Fjord Tours you can explore more of the magical fjord
            landscapes with tours and activities on and around the fjords of
            Norway
          </Text>

          <Button color="blue" fullWidth mt="md" radius="md">
            Book classic tour now
          </Button>
        </Card>
      </Parallax>
    </Center>
  );
}

Simple usage

Below a super simple example of how to use the Parallax component.

Parallax

Amazing parallax effect component. Hover to see the effect.

import { Parallax } from '@gfazioli/mantine-parallax';

function Demo() {
  return (
    <Center w="100%" h={300}>
      <Parallax w={300} h={200}>
        <Title>Parallax</Title>
        <Text>
          Amazing parallax effect component. Hover to see the effect.
        </Text>
      </Parallax>
    </Center>
  );
}

Parallax Effects

In addition to the classic Apple TV Card effect, you can use the Parallax component to create a parallax effects both for the background and for the content. You may use the backgroundParallax and backgroundParallaxThreshold props to enable and manage the parallax effect.

Background

Here is an example of the parallax effect used for the background.

Perspective
Initial perspective
Initial rotation x
Initial rotation y
Initial rotation z
Initial skew x
Initial skew y
Threshold
Hover scale
Transition duration
Light intensity
Light size
Light color
Light gradient type
Light gradient angle
Background parallax threshold
import { Parallax } from '@gfazioli/mantine-parallax';
function Demo() {
  return (
    <Center w="100%" h={400}>
      <Parallax
        lightEffect
        lightIntensity={0.1}
        lightColor="rgba(255, 255, 255, .5)"
        lightGradientType="linear"
        lightGradientAngle={-120}
        backgroundParallax
        w={400}
        h={300}
        backgroundImage="https://raw.githubusercontent.com/mantinedev/mantine/master/.demo/images/bg-1.png"
      />
    </Center>
  );
}

Parallax.Layer

The Parallax.Layer compound component provides a cleaner way to create content parallax effects. Each layer has a depth prop that controls how much it moves relative to the card rotation — higher values move more.

Depth 1

Parallax Layers

Each layer moves at a different speed based on its depth.

Hover me!

import { Parallax } from '@gfazioli/mantine-parallax';

function Demo() {
  return (
    <Center w="100%" h={400}>
      <Parallax w={340} h={280} bg="dark.9" p="xl" radius={16}>
        <Parallax.Layer depth={1}>
          <Text size="xs" c="dimmed" tt="uppercase" fw={700}>
            Depth 1
          </Text>
        </Parallax.Layer>
        <Parallax.Layer depth={3}>
          <Title order={2} c="white" mt="xs">
            Parallax Layers
          </Title>
        </Parallax.Layer>
        <Parallax.Layer depth={6}>
          <Text c="yellow.4" mt="sm" fw={500}>
            Each layer moves at a different speed based on its depth.
          </Text>
        </Parallax.Layer>
        <Parallax.Layer depth={10}>
          <Text c="blue.4" mt="lg" size="xl" fw={900}
            style={{ textShadow: '0 2px 8px rgba(0,0,0,0.3)' }}
          >
            Hover me!
          </Text>
        </Parallax.Layer>
      </Parallax>
    </Center>
  );
}

Content (legacy)

You can also use the contentParallax and contentParallaxDistance props to enable content parallax. This approach uses cloneElement internally and applies depth based on child index. For more control, prefer Parallax.Layer.

Parallax

Amazing parallax effect component. Hover to see the effect.

Perspective
Threshold
Hover scale
Transition duration
Light intensity
Light size
Light color
Light gradient type
Light gradient angle
Content parallax distance
import { Parallax } from '@gfazioli/mantine-parallax';

function Demo() {
  return (
    <Center w="100%" h={300}>
      <Parallax  lightIntensity={0.1} lightColor="rgba(255, 255, 255, .5)" contentParallax contentParallaxDistance={1} w={300} h={200} p={16} bg="dark.5">
        <Title c="gray.2">Parallax</Title>
        <Text c="yellow.5">
          Amazing parallax effect component. Hover to see the effect.
        </Text>
      </Parallax>
    </Center>
  );
}

Example: Complex

Below a more complex example of how to use the Parallax component.

Parallax

Amazing parallax effect component. Hover to see the effect.

Perspective
Threshold
Hover scale
Transition duration
Light intensity
Light size
Light color
Light gradient type
Light gradient angle
Background parallax threshold
Content parallax distance
import { Parallax } from '@gfazioli/mantine-parallax';
function Demo() {
  return (
    <Center w="100%" h={300} bg="dark.7">
      <Parallax
        lightEffect
        lightIntensity={0.1}
        lightColor="rgba(255, 255, 255, .5)"
        backgroundParallax
        contentParallax
        contentParallaxDistance={1}
        w={400}
        h={200}
        p={16}
        radius={16}
        backgroundImage="https://raw.githubusercontent.com/mantinedev/mantine/master/.demo/images/bg-1.png"
        style={{
          border: "1px solid #666",
        }}
      >
        <Title c="gray.2">Parallax</Title>
        <Text c="gray.2" fw="bold">
          Amazing parallax effect component. Hover to see the effect.
        </Text>
      </Parallax>
    </Center>
  );
}

Spring Physics

Enable springEffect to replace CSS transitions with spring-based physics animation. The card movement becomes more natural, with overshoot and oscillation. Adjust springStiffness (default 150, higher = snappier) and springDamping (default 12, higher = less bounce) to fine-tune the feel. Works with all effects including shadow, light, glare, and Parallax.Layer.

Norway

Norway Fjord Adventures

On Sale

With Fjord Tours you can explore more of the magical fjord landscapes with tours and activities on and around the fjords of Norway

Spring stiffness
Spring damping
Threshold
import { Parallax } from '@gfazioli/mantine-parallax';

function Demo() {
  return (
    <Center w="100%" h={500}>
      <Parallax  springEffect springStiffness={360} springDamping={3} lightEffect lightOverlay shadowEffect w={400} radius="md">
        <Card shadow="sm" padding="lg" radius="md" withBorder>
          <Card.Section>
            <Image
              src="https://raw.githubusercontent.com/mantinedev/mantine/master/.demo/images/bg-8.png"
              height={160}
              alt="Norway"
            />
          </Card.Section>

          <Group justify="space-between" mt="md" mb="xs">
            <Text fw={500}>Norway Fjord Adventures</Text>
            <Badge color="pink">On Sale</Badge>
          </Group>

          <Text size="sm" c="dimmed">
            With Fjord Tours you can explore more of the magical fjord
            landscapes with tours and activities on and around the fjords of
            Norway
          </Text>

          <Button color="blue" fullWidth mt="md" radius="md">
            Book classic tour now
          </Button>
        </Card>
      </Parallax>
    </Center>
  );
}

Glare Effect

The glareEffect prop adds a reflective glare that follows the cursor, simulating a glossy surface. You can customize it with glareColor, glareMaxOpacity, glareSize, and glareOverlay. Combine it with lightEffect and shadowEffect for the full Apple TV Card experience.

Norway

Norway Fjord Adventures

On Sale

With Fjord Tours you can explore more of the magical fjord landscapes with tours and activities on and around the fjords of Norway

Glare color
Glare max opacity
Glare size
import { Parallax } from '@gfazioli/mantine-parallax';

function Demo() {
  return (
    <Center w="100%" h={500}>
      <Parallax  glareEffect lightEffect shadowEffect w={400} radius="md">
        <Card shadow="sm" padding="lg" radius="md" withBorder>
          <Card.Section>
            <Image
              src="https://raw.githubusercontent.com/mantinedev/mantine/master/.demo/images/bg-8.png"
              height={160}
              alt="Norway"
            />
          </Card.Section>

          <Group justify="space-between" mt="md" mb="xs">
            <Text fw={500}>Norway Fjord Adventures</Text>
            <Badge color="pink">On Sale</Badge>
          </Group>

          <Text size="sm" c="dimmed">
            With Fjord Tours you can explore more of the magical fjord
            landscapes with tours and activities on and around the fjords
            of Norway
          </Text>

          <Button color="blue" fullWidth mt="md" radius="md">
            Book classic tour now
          </Button>
        </Card>
      </Parallax>
    </Center>
  );
}

Example: Dynamic Shadow

The shadowEffect prop enables a dynamic shadow that moves opposite to the card rotation, simulating a light source from above. You can customize it with shadowColor, shadowBlur, and shadowOffset.

Card image

Dynamic Shadow

Enable shadowEffect and tilt the card to see the shadow follow the rotation.

Shadow color
Shadow blur
Shadow offset
import { Parallax } from '@gfazioli/mantine-parallax';
function Demo() {
  return (
    <Center w="100%" h={400}>
      <Parallax
        shadowEffect
        w={340}
        lightEffect
        lightOverlay
        lightIntensity={0.05}
        lightSize={60}
        radius="md"
      >
        <Card shadow="none" padding="lg" radius="md" withBorder>
          <Card.Section>
            <Image
              src="https://raw.githubusercontent.com/mantinedev/mantine/master/.demo/images/bg-2.png"
              height={160}
              alt="Card image"
            />
          </Card.Section>
          <Group justify="space-between" mt="md" mb="xs">
            <Title order={4}>Dynamic Shadow</Title>
          </Group>
          <Text size="sm" c="dimmed">
            Enable shadowEffect and tilt the card to see the shadow
            follow the rotation.
          </Text>
        </Card>
      </Parallax>
    </Center>
  );
}

Example: onRotationChange

The onRotationChange callback receives { rotateX, rotateY, isHovering } on every rotation update. You can use it to synchronize external UI elements, drive animations, or display debug info.

Hover this card

The rotation values are displayed below in real time.

Idle
X: 0.0° Y: 0.0°
import { useState } from 'react';
import { Parallax } from '@gfazioli/mantine-parallax';

function Demo() {
  const [info, setInfo] = useState({ rotateX: 0, rotateY: 0, isHovering: false });

  return (
    <Stack align="center" gap="md">
      <Center w="100%" h={300}>
        <Parallax w={300} lightEffect lightOverlay onRotationChange={setInfo} radius="md">
          <Card shadow="sm" padding="lg" radius="md" withBorder>
            <Text fw={500}>Hover this card</Text>
            <Text size="sm" c="dimmed">
              The rotation values are displayed below in real time.
            </Text>
          </Card>
        </Parallax>
      </Center>
      <Group>
        <Badge color={info.isHovering ? 'green' : 'gray'} variant="filled">
          {info.isHovering ? 'Hovering' : 'Idle'}
        </Badge>
        <Code>
          X: {info.rotateX.toFixed(1)}° Y: {info.rotateY.toFixed(1)}°
        </Code>
      </Group>
    </Stack>
  );
}

Example: Shadow

Give free rein to your creativity. You can use the Parallax component to create shading effects.

Parallax

Amazing parallax effect component. Hover to see the effect.

Perspective
Threshold
Hover scale
Transition duration
Light intensity
Light size
Light color
Light gradient type
Light gradient angle
Background parallax threshold
Content parallax distance
import { Parallax } from '@gfazioli/mantine-parallax';

function Demo() {
  return (
    <Center w="100%" h={300}>
      <Parallax  lightIntensity={0.1} lightColor="rgba(255, 255, 255, .5)" backgroundParallax contentParallax contentParallaxDistance={4} p={32} bg="tomato" radius={16}>
        <Box
          w={300}
          h={200}
          style={{
            position: "absolute",
            boxShadow: "0 0 12px rgba(0, 0, 0, 1)",
            backgroundColor: "rgba(0, 0, 0, 0.5)",
            borderRadius: "16px",
          }}
        />
        <Paper w={300} h={200} bg="gray.9" radius={16} p={16}>
          <Title c="white">Parallax</Title>
          <Text c="white">
            Amazing parallax effect component. Hover to see the effect.
          </Text>
        </Paper>
      </Parallax>
    </Center>
  );
}

Example: Presentation

A more complete example showing how multiple features can be combined to create engaging presentation cards.

Norway

Norway Fjord Adventures

On Sale

With Fjord Tours you can explore more of the magical fjord landscapes with tours and activities on and around the fjords of Norway

Norway

Norway Fjord Adventures

On Sale

With Fjord Tours you can explore more of the magical fjord landscapes with tours and activities on and around the fjords of Norway

Norway

Norway Fjord Adventures

On Sale

With Fjord Tours you can explore more of the magical fjord landscapes with tours and activities on and around the fjords of Norway

import { Stack } from '@mantine/core';
import { Parallax } from '@gfazioli/mantine-parallax';
import { PresentationCard } from './PresentationCard';

function Demo() {
  const presentationProps = {
    initialRotationX: 60,
    initialSkewX: -30,
    initialSkewY: 30,
    initialPerspective: 10000,
    disabled: true,
  };

  return (
    <Stack w="100%" h={500} align="center">
      <Parallax w={400} {...presentationProps} style={{ position: 'absolute', top: 160 }}>
        <PresentationCard imgIndex={1} />
      </Parallax>
      <Parallax w={400} {...presentationProps} style={{ position: 'absolute', top: 80 }}>
        <PresentationCard imgIndex={2} />
      </Parallax>
      <Parallax w={400} {...presentationProps} style={{ position: 'absolute', top: 0 }}>
        <PresentationCard imgIndex={3} />
      </Parallax>
    </Stack>
  );
}