Aug 14, 2024

Framer

Framer

Framer

Intercom Website Scroll Effect

Intercom Website Scroll Effect

Intercom Website Scroll Effect

Here is a scroll effect, I created for a client for a project that didn't work out. He wanted scroll effects exactly as the intercom website. I made it, and made it responsive for all screen sizes!

Intercom Website Scroll Effect
Intercom Website Scroll Effect
Intercom Website Scroll Effect

I started understanding the effect on mobile and desktop from the intercom website. Though the effects looked easy, but in implementation it's quite tiring and long process to make that happen.

So, I started experimenting on how can I create this. I went with different option like variant switching, scroll animations, but to keep it simple, I went with 2 components, one for desktop, and one for mobile devices.

For desktop variant, its a component, where I have 10 versions and each connected with hover property, which displays the image.

That is fairly simple to achieve, just complicated to update!

Next we move on to the tablet version, in this the trick is to use a code override to make it work while the user scrolls.

So the code is given below, and the rest of the variant is similar to the desktop version.

Code Override

import React, { useState, ComponentType, useRef, useEffect } from "react"
import { useScroll, useMotionValueEvent } from "framer-motion"

const VARIANT_LENGTH = 11

export const withScrollVariants = (Component): ComponentType => {
    const variants = Array.from(
        { length: VARIANT_LENGTH },
        (_, i) => `Variant ${i}`
    )

    return (props) => {
        const [variantIndex, setVariantIndex] = useState(0)
        const [imagesLoaded, setImagesLoaded] = useState(false)
        const ref = useRef(null)
        const { scrollYProgress } = useScroll({
            target: ref,
            offset: ["start 0.65", "end 0.7"],
        })

        useEffect(() => {
            const imageSources = []
            document.querySelectorAll("img").forEach((imgElement) => {
                imageSources.push(imgElement.src)
            })

            const imagePromises = imageSources.map((src) => {
                return new Promise((resolve, reject) => {
                    const img = new Image()
                    img.onload = () => resolve(src)
                    img.onerror = () => reject(src)
                    img.src = src
                })
            })

            Promise.all(imagePromises)
                .then(() => setImagesLoaded(true))
                .catch(() => setImagesLoaded(false))
        }, [])

        useEffect(() => {
            const newVariantIndex =
                Math.round(scrollYProgress.current * (VARIANT_LENGTH - 2)) + 1

            setVariantIndex(newVariantIndex)
        }, [scrollYProgress.current])

        useMotionValueEvent(scrollYProgress, "change", (currentProgress) => {
            const newVariantIndex =
                Math.round(scrollYProgress.current * (VARIANT_LENGTH - 2)) + 1

            if (newVariantIndex !== variantIndex && imagesLoaded) {
                setVariantIndex(newVariantIndex)
            }
        })

        return (
            <>
                <div style={{ display: "none" }}>
                    {variants.map((variant) => (
                        <Component key={variant} {...props} variant={variant} />
                    ))}
                </div>
                <Component
                    {...props}
                    variant={variants[variantIndex]}
                    ref={ref}
                />
            </>
        )
    }
}

Now using this code override, we will make the mobile version. Trick with the mobile version is that it should stay sticky on the bottom left as it is on the intercom website.

This is the only major change in the component, rest of it is fairly simple.

So, this is how I made the interaction work, and managed to make it responsive in framer. Though I don't like the fact that it's complicated to change the information, and add new items, but I had to make it work in less than 4hrs, so I guess this can work.

Let me know your thoughts, and if you like this, share this free remix on X with your community.

See you soon!

Design Strategist

Get Reliable Designs for Uninterrupted Growth

Achieve stunning, consistent marketing visuals with BLC's design service. Quick turnarounds and personalized attention & satisfaction guaranteed.

Book A Call

Aman BG
Aman

Design Strategist

Get Reliable Designs for Uninterrupted Growth

Achieve stunning, consistent marketing visuals with BLC's design service. Quick turnarounds and personalized attention & satisfaction guaranteed.

Book A Call

Aman BG
Aman

Design Strategist

Get Reliable Designs for Uninterrupted Growth

Achieve stunning, consistent marketing visuals with BLC's design service. Quick turnarounds and personalized attention & satisfaction guaranteed.

Book A Call

Aman BG
Aman

Know your designer

Know your designer

Know your designer

Connect with me to gain insights, access valuable resources, and see behind the scenes content. Follow me to stay updated with tips, tricks, and design inspiration.

Connect with me to gain insights, access valuable resources, and see behind the scenes content. Follow me to stay updated with tips, tricks, and design inspiration.

X / Twitter

Follow me here for updates, tips, and insights. I'm most active here, sharing everything from important news to casual thoughts.

Instagram

Find videos on important topics, resources, and other design related content. Follow for tutorials and design inspiration!

Instagram

Find videos on important topics, resources, and other design related content. Follow for tutorials and design inspiration!

Figma Community

Access free resources and assets trusted by 6K+ designers. Follow me on Figma to enhance your design projects.

Figma Community

Access free resources and assets trusted by 6K+ designers. Follow me on Figma to enhance your design projects.

Add social share buttons to your Framer website.

Let visitors share your page to their social media accounts in one click.