3D Card Flip Override

Nandi Muzsik

How can I improve Framer Uni?

Let me know if there’s a missing feature or something that could be improved.

Share feedback

Nandi Muzsik

How can I improve Framer Uni?

Let me know if there’s a missing feature or something that could be improved.

Share feedback

Effect

3D Card Flip Override

This is a code override for Framer that can be applied to a component to give it a 3D card-like appearance that flips to reveal its back side upon clicking. Feel free to use it on your website for a unique touch.

image of Nandi Muzsik
profile image of Joshua Guo

Created by

3D Card Flip Override
3D Card Flip Override
3D Card Flip Override

About the resource

Ensure that the component you apply this code override to has a variant named "Front" and another named "Back". The "Front" variant will display upon page load, and the "Back" variant will appear when the component is clicked.

3D card flip code override

You can also copy this code to create a new code override in your project, which will allow the card component to flip upon click.

About the resource

Ensure that the component you apply this code override to has a variant named "Front" and another named "Back". The "Front" variant will display upon page load, and the "Back" variant will appear when the component is clicked.

3D card flip code override

You can also copy this code to create a new code override in your project, which will allow the card component to flip upon click.

About the resource

Ensure that the component you apply this code override to has a variant named "Front" and another named "Back". The "Front" variant will display upon page load, and the "Back" variant will appear when the component is clicked.

3D card flip code override

You can also copy this code to create a new code override in your project, which will allow the card component to flip upon click.

import type { ComponentType } from "react"
import { motion, useSpring } from "framer-motion"
import React, { useState, useRef, useEffect } from "react"

// Learn more: https://www.framer.com/docs/guides/overrides/

//Spring animation parameters
const spring = {
    type: "spring",
    stiffness: 300,
    damping: 40,
}

/**
 * 3D Flip
 * Created By Joshua Guo
 *
 * @framerSupportedLayoutWidth fixed
 * @framerSupportedLayoutHeight fixed
 */

export function withClick(Component): ComponentType {
    return (props) => {
        const [isFlipped, setIsFlipped] = useState(false)

        const handleClick = () => {
            setIsFlipped((prevState) => !prevState)
        }

        const [rotateXaxis, setRotateXaxis] = useState(0)
        const [rotateYaxis, setRotateYaxis] = useState(0)
        const ref = useRef(null)

        const handleMouseMove = (event) => {
            const element = ref.current
            const elementRect = element.getBoundingClientRect()
            const elementWidth = elementRect.width
            const elementHeight = elementRect.height
            const elementCenterX = elementWidth / 2
            const elementCenterY = elementHeight / 2
            const mouseX = event.clientY - elementRect.y - elementCenterY
            const mouseY = event.clientX - elementRect.x - elementCenterX
            const degreeX = (mouseX / elementWidth) * 20 //The number is the rotation factor
            const degreeY = (mouseY / elementHeight) * 20 //The number is the rotation factor
            setRotateXaxis(degreeX)
            setRotateYaxis(degreeY)
        }

        const handleMouseEnd = () => {
            setRotateXaxis(0)
            setRotateYaxis(0)
        }

        const dx = useSpring(0, spring)
        const dy = useSpring(0, spring)

        useEffect(() => {
            dx.set(-rotateXaxis)
            dy.set(rotateYaxis)
        }, [rotateXaxis, rotateYaxis])

        return (
            <motion.div
                onClick={handleClick}
                transition={spring}
                style={{
                    perspective: "1200px",
                    transformStyle: "preserve-3d",
                    width: `${props.width}`,
                    height: `${props.height}`,
                }}
            >
                <motion.div
                    ref={ref}
                    whileHover={{ scale: 1.1 }} //Change the scale of zooming in when hovering
                    onMouseMove={handleMouseMove}
                    onMouseLeave={handleMouseEnd}
                    transition={spring}
                    style={{
                        width: "100%",
                        height: "100%",
                        rotateX: dx,
                        rotateY: dy,
                    }}
                >
                    <div
                        style={{
                            perspective: "1200px",
                            transformStyle: "preserve-3d",
                            width: "100%",
                            height: "100%",
                        }}
                    >
                        <motion.div
                            animate={{ rotateY: isFlipped ? -180 : 0 }}
                            transition={spring}
                            style={{
                                width: "100%",
                                height: "100%",
                                zIndex: isFlipped ? 0 : 1,
                                backfaceVisibility: "hidden",
                                position: "absolute",
                            }}
                        >
                            <Component
                                {...props}
                                variant="Front"
                                style={{
                                    width: "100%",
                                    height: "100%",
                                }}
                            />
                        </motion.div>
                        <motion.div
                            initial={{ rotateY: 180 }}
                            animate={{ rotateY: isFlipped ? 0 : 180 }}
                            transition={spring}
                            style={{
                                width: "100%",
                                height: "100%",
                                zIndex: isFlipped ? 1 : 0,
                                backfaceVisibility: "hidden",
                                position: "absolute",
                            }}
                        >
                            <Component
                                {...props}
                                variant="Back"
                                style={{
                                    width: "100%",
                                    height: "100%",
                                }}
                            />
                        </motion.div>
                    </div>
                </motion.div>
            </motion.div>
        )
    }
}
import type { ComponentType } from "react"
import { motion, useSpring } from "framer-motion"
import React, { useState, useRef, useEffect } from "react"

// Learn more: https://www.framer.com/docs/guides/overrides/

//Spring animation parameters
const spring = {
    type: "spring",
    stiffness: 300,
    damping: 40,
}

/**
 * 3D Flip
 * Created By Joshua Guo
 *
 * @framerSupportedLayoutWidth fixed
 * @framerSupportedLayoutHeight fixed
 */

export function withClick(Component): ComponentType {
    return (props) => {
        const [isFlipped, setIsFlipped] = useState(false)

        const handleClick = () => {
            setIsFlipped((prevState) => !prevState)
        }

        const [rotateXaxis, setRotateXaxis] = useState(0)
        const [rotateYaxis, setRotateYaxis] = useState(0)
        const ref = useRef(null)

        const handleMouseMove = (event) => {
            const element = ref.current
            const elementRect = element.getBoundingClientRect()
            const elementWidth = elementRect.width
            const elementHeight = elementRect.height
            const elementCenterX = elementWidth / 2
            const elementCenterY = elementHeight / 2
            const mouseX = event.clientY - elementRect.y - elementCenterY
            const mouseY = event.clientX - elementRect.x - elementCenterX
            const degreeX = (mouseX / elementWidth) * 20 //The number is the rotation factor
            const degreeY = (mouseY / elementHeight) * 20 //The number is the rotation factor
            setRotateXaxis(degreeX)
            setRotateYaxis(degreeY)
        }

        const handleMouseEnd = () => {
            setRotateXaxis(0)
            setRotateYaxis(0)
        }

        const dx = useSpring(0, spring)
        const dy = useSpring(0, spring)

        useEffect(() => {
            dx.set(-rotateXaxis)
            dy.set(rotateYaxis)
        }, [rotateXaxis, rotateYaxis])

        return (
            <motion.div
                onClick={handleClick}
                transition={spring}
                style={{
                    perspective: "1200px",
                    transformStyle: "preserve-3d",
                    width: `${props.width}`,
                    height: `${props.height}`,
                }}
            >
                <motion.div
                    ref={ref}
                    whileHover={{ scale: 1.1 }} //Change the scale of zooming in when hovering
                    onMouseMove={handleMouseMove}
                    onMouseLeave={handleMouseEnd}
                    transition={spring}
                    style={{
                        width: "100%",
                        height: "100%",
                        rotateX: dx,
                        rotateY: dy,
                    }}
                >
                    <div
                        style={{
                            perspective: "1200px",
                            transformStyle: "preserve-3d",
                            width: "100%",
                            height: "100%",
                        }}
                    >
                        <motion.div
                            animate={{ rotateY: isFlipped ? -180 : 0 }}
                            transition={spring}
                            style={{
                                width: "100%",
                                height: "100%",
                                zIndex: isFlipped ? 0 : 1,
                                backfaceVisibility: "hidden",
                                position: "absolute",
                            }}
                        >
                            <Component
                                {...props}
                                variant="Front"
                                style={{
                                    width: "100%",
                                    height: "100%",
                                }}
                            />
                        </motion.div>
                        <motion.div
                            initial={{ rotateY: 180 }}
                            animate={{ rotateY: isFlipped ? 0 : 180 }}
                            transition={spring}
                            style={{
                                width: "100%",
                                height: "100%",
                                zIndex: isFlipped ? 1 : 0,
                                backfaceVisibility: "hidden",
                                position: "absolute",
                            }}
                        >
                            <Component
                                {...props}
                                variant="Back"
                                style={{
                                    width: "100%",
                                    height: "100%",
                                }}
                            />
                        </motion.div>
                    </div>
                </motion.div>
            </motion.div>
        )
    }
}
import type { ComponentType } from "react"
import { motion, useSpring } from "framer-motion"
import React, { useState, useRef, useEffect } from "react"

// Learn more: https://www.framer.com/docs/guides/overrides/

//Spring animation parameters
const spring = {
    type: "spring",
    stiffness: 300,
    damping: 40,
}

/**
 * 3D Flip
 * Created By Joshua Guo
 *
 * @framerSupportedLayoutWidth fixed
 * @framerSupportedLayoutHeight fixed
 */

export function withClick(Component): ComponentType {
    return (props) => {
        const [isFlipped, setIsFlipped] = useState(false)

        const handleClick = () => {
            setIsFlipped((prevState) => !prevState)
        }

        const [rotateXaxis, setRotateXaxis] = useState(0)
        const [rotateYaxis, setRotateYaxis] = useState(0)
        const ref = useRef(null)

        const handleMouseMove = (event) => {
            const element = ref.current
            const elementRect = element.getBoundingClientRect()
            const elementWidth = elementRect.width
            const elementHeight = elementRect.height
            const elementCenterX = elementWidth / 2
            const elementCenterY = elementHeight / 2
            const mouseX = event.clientY - elementRect.y - elementCenterY
            const mouseY = event.clientX - elementRect.x - elementCenterX
            const degreeX = (mouseX / elementWidth) * 20 //The number is the rotation factor
            const degreeY = (mouseY / elementHeight) * 20 //The number is the rotation factor
            setRotateXaxis(degreeX)
            setRotateYaxis(degreeY)
        }

        const handleMouseEnd = () => {
            setRotateXaxis(0)
            setRotateYaxis(0)
        }

        const dx = useSpring(0, spring)
        const dy = useSpring(0, spring)

        useEffect(() => {
            dx.set(-rotateXaxis)
            dy.set(rotateYaxis)
        }, [rotateXaxis, rotateYaxis])

        return (
            <motion.div
                onClick={handleClick}
                transition={spring}
                style={{
                    perspective: "1200px",
                    transformStyle: "preserve-3d",
                    width: `${props.width}`,
                    height: `${props.height}`,
                }}
            >
                <motion.div
                    ref={ref}
                    whileHover={{ scale: 1.1 }} //Change the scale of zooming in when hovering
                    onMouseMove={handleMouseMove}
                    onMouseLeave={handleMouseEnd}
                    transition={spring}
                    style={{
                        width: "100%",
                        height: "100%",
                        rotateX: dx,
                        rotateY: dy,
                    }}
                >
                    <div
                        style={{
                            perspective: "1200px",
                            transformStyle: "preserve-3d",
                            width: "100%",
                            height: "100%",
                        }}
                    >
                        <motion.div
                            animate={{ rotateY: isFlipped ? -180 : 0 }}
                            transition={spring}
                            style={{
                                width: "100%",
                                height: "100%",
                                zIndex: isFlipped ? 0 : 1,
                                backfaceVisibility: "hidden",
                                position: "absolute",
                            }}
                        >
                            <Component
                                {...props}
                                variant="Front"
                                style={{
                                    width: "100%",
                                    height: "100%",
                                }}
                            />
                        </motion.div>
                        <motion.div
                            initial={{ rotateY: 180 }}
                            animate={{ rotateY: isFlipped ? 0 : 180 }}
                            transition={spring}
                            style={{
                                width: "100%",
                                height: "100%",
                                zIndex: isFlipped ? 1 : 0,
                                backfaceVisibility: "hidden",
                                position: "absolute",
                            }}
                        >
                            <Component
                                {...props}
                                variant="Back"
                                style={{
                                    width: "100%",
                                    height: "100%",
                                }}
                            />
                        </motion.div>
                    </div>
                </motion.div>
            </motion.div>
        )
    }
}

Framer Navigator

Learn the fundamentals of Framer for free.

Build your ideas with ease by learning the basics of website building with Framer.

Nandi portrait's background
Nandi's portrait

Framer Navigator

Learn the fundamentals of Framer for free.

Build your ideas with ease by learning the basics of website building with Framer.

Nandi portrait's background
Nandi's portrait

Framer Navigator

Learn the fundamentals of Framer for free.

Build your ideas with ease by learning the basics of website building with Framer.

Nandi portrait's background
Nandi's portrait

More resources

More resources

  • Interactive Isometric 3D Hero

    Interactive Isometric 3D Hero

    Effect

    Interactive Isometric 3D Hero

    Interactive Isometric 3D Hero

    Effect

    Interactive Isometric 3D Hero

    Interactive Isometric 3D Hero

    Effect

  • Show Once Code Override for Framer

    Show Once Code Override for Framer

    Effect

    Show Once Code Override for Framer

    Show Once Code Override for Framer

    Effect

    Show Once Code Override for Framer

    Show Once Code Override for Framer

    Effect