Scroll Highlight Animation Override for Framer

Scroll Highlight Animation Override for Framer

Scroll Highlight Animation Override for Framer

Scroll Highlight Animation Override for Framer

Website animation

Website animation

Website animation

Website animation

Scroll Highlight Animation Override for Framer

Scroll Highlight Animation Override for Framer

Scroll Highlight Animation Override for Framer

Scroll Highlight Animation Override for Framer

This is a Framer implementation of the scroll highlight animation, shared by Jhey Tompkins. Scroll down to learn how you can apply it to your Framer websites.

This is a Framer implementation of the scroll highlight animation, shared by Jhey Tompkins. Scroll down to learn how you can apply it to your Framer websites.

This is a Framer implementation of the scroll highlight animation, shared by Jhey Tompkins. Scroll down to learn how you can apply it to your Framer websites.

This is a Framer implementation of the scroll highlight animation, shared by Jhey Tompkins. Scroll down to learn how you can apply it to your Framer websites.

Scroll Highlight Animation Override for Framer
Scroll Highlight Animation Override for Framer
Scroll Highlight Animation Override for Framer
Scroll Highlight Animation Override for Framer

Features

This is a Framer code override that you can apply to any text layer to achieve the scroll highlight animation effect.

Here's how it works: it looks for parts of your text that have an underline decoration. So, if you want to highlight a sentence, you need to select it, head over to styles, hit the plus button, and add an underline decoration style.

adding underline to a text in Framer

Next, you ought to copy the code override (from below) and implement it into your project. You can do this by heading to assets, scrolling down to code, and clicking the plus button.

As you can see, the code override contains three "export function" instances. Each one presents the same effect, but with different highlight colors.

Below, you will see sections highlighted in blue where you can modify the highlight color. You're required to provide the RGBA values of the color in these spots, where "0.5" represents 50% opacity.

The part of the code highlighted in orange represent place where you can modify the color of the highlighted text. If you prefer to retain the text color, you can simply replace this with "color: inherit;".

editing the scroll highlight override in Framer
Step 01 outline

Step / 01

Remix the project.

Step 2 outline

Step / 02

Copy the code override.

Step 3 outline

Step / 03

Paste the code override into your Framer project.

Code override for scroll highlight animation

Feel free to copy the code from below and create a code override for yourself in your Framer project.

import { ComponentType, useEffect, useState } from "react"

export function withHighlightColor1(Component): ComponentType {
    return (props: any) => {
        const [isVisible, setIsVisible] = useState(false)

        useEffect(() => {
            const elements = document.querySelectorAll(
                `.${props.className} [style*="--framer-text-decoration: underline"]`
            )

            // Now, let's add a parent <mark> tag to the selected elements
            elements.forEach((element) => {
                element.style.removeProperty("--framer-text-decoration")

                const markElement = document.createElement("mark")
                const spanElement = document.createElement("span")

                // Wrap the element with mark
                element.parentNode.insertBefore(markElement, element)
                markElement.appendChild(element)

                // Wrap the content of the element with span
                while (element.firstChild) {
                    spanElement.appendChild(element.firstChild)
                }

                element.appendChild(spanElement)
                setIsVisible(true)
            })

            const handle = (entries) => {
                entries.forEach((entry) => {
                    const highlightedValue =
                        entry.target.style.getPropertyValue("--highlighted")
                    console.log("handle")
                    if (!highlightedValue || parseInt(highlightedValue) === 0) {
                        entry.target.style.setProperty(
                            "--highlighted",
                            entry.isIntersecting ? "1" : "0"
                        )
                    }
                })
            }
            const observer = new IntersectionObserver(handle, {
                threshold: 1.0,
            })
            elements.forEach((M) => observer.observe(M))
        }, [props])

        return (
            <>
                <style>{`
.${props.className} mark {
--highlighted: 0;
--highlight: rgba(0, 128, 255, 0.5);
background: transparent;
}

.${props.className} mark span {
background: linear-gradient(120deg, var(--highlight) 50%, transparent 50%) 110% 0 / 200% 100% no-repeat;
background-position: calc((1 - var(--highlighted)) * 110%) 0;
transition: background-position 1s;
color: white;
}
`}</style>
                <Component
                    {...props}
                    style={!isVisible ? { opacity: 0 } : {}}
                />
            </>
        )
    }
}

export function withHighlightColor2(Component): ComponentType {
    return (props: any) => {
        const [isVisible, setIsVisible] = useState(false)

        useEffect(() => {
            const elements = document.querySelectorAll(
                `.${props.className} [style*="--framer-text-decoration: underline"]`
            )

            // Now, let's add a parent <mark> tag to the selected elements
            elements.forEach((element) => {
                element.style.removeProperty("--framer-text-decoration")

                const markElement = document.createElement("mark")
                const spanElement = document.createElement("span")

                // Wrap the element with mark
                element.parentNode.insertBefore(markElement, element)
                markElement.appendChild(element)

                // Wrap the content of the element with span
                while (element.firstChild) {
                    spanElement.appendChild(element.firstChild)
                }

                element.appendChild(spanElement)
                setIsVisible(true)
            })

            const handle = (entries) => {
                entries.forEach((entry) => {
                    const highlightedValue =
                        entry.target.style.getPropertyValue("--highlighted")
                    if (!highlightedValue || parseInt(highlightedValue) === 0) {
                        entry.target.style.setProperty(
                            "--highlighted",
                            entry.isIntersecting ? "1" : "0"
                        )
                    }
                })
            }
            const observer = new IntersectionObserver(handle, {
                threshold: 1.0,
            })
            elements.forEach((M) => observer.observe(M))
        }, [props])

        return (
            <>
                <style>{`
.${props.className} mark {
--highlighted: 0;
--highlight: rgba(255, 195, 0, 0.8);
background: transparent;
}

.${props.className} mark span {
background: linear-gradient(120deg, var(--highlight) 50%, transparent 50%) 110% 0 / 200% 100% no-repeat;
background-position: calc((1 - var(--highlighted)) * 110%) 0;
transition: background-position 1s;
color: black;
}
`}</style>
                <Component
                    {...props}
                    style={!isVisible ? { opacity: 0 } : {}}
                />
            </>
        )
    }
}

export function withHighlightColor3(Component): ComponentType {
    return (props: any) => {
        const [isVisible, setIsVisible] = useState(false)

        useEffect(() => {
            const elements = document.querySelectorAll(
                `.${props.className} [style*="--framer-text-decoration: underline"]`
            )

            // Now, let's add a parent <mark> tag to the selected elements
            elements.forEach((element) => {
                element.style.removeProperty("--framer-text-decoration")

                const markElement = document.createElement("mark")
                const spanElement = document.createElement("span")

                // Wrap the element with mark
                element.parentNode.insertBefore(markElement, element)
                markElement.appendChild(element)

                // Wrap the content of the element with span
                while (element.firstChild) {
                    spanElement.appendChild(element.firstChild)
                }

                element.appendChild(spanElement)
                setIsVisible(true)
            })

            const handle = (entries) => {
                entries.forEach((entry) => {
                    const highlightedValue =
                        entry.target.style.getPropertyValue("--highlighted")
                    if (!highlightedValue || parseInt(highlightedValue) === 0) {
                        entry.target.style.setProperty(
                            "--highlighted",
                            entry.isIntersecting ? "1" : "0"
                        )
                    }
                })
            }
            const observer = new IntersectionObserver(handle, {
                threshold: 1.0,
            })
            elements.forEach((M) => observer.observe(M))
        }, [props])

        return (
            <>
                <style>{`
.${props.className} mark {
--highlighted: 0;
--highlight: rgba(140, 0, 255, 0.5);
background: transparent;
}

.${props.className} mark span {
background: linear-gradient(120deg, var(--highlight) 50%, transparent 50%) 110% 0 / 200% 100% no-repeat;
background-position: calc((1 - var(--highlighted)) * 110%) 0;
transition: background-position 1s;
color: white;
}
`}</style>
                <Component
                    {...props}
                    style={!isVisible ? { opacity: 0 } : {}}
                />
            </>
        )
    }
}
import { ComponentType, useEffect, useState } from "react"

export function withHighlightColor1(Component): ComponentType {
    return (props: any) => {
        const [isVisible, setIsVisible] = useState(false)

        useEffect(() => {
            const elements = document.querySelectorAll(
                `.${props.className} [style*="--framer-text-decoration: underline"]`
            )

            // Now, let's add a parent <mark> tag to the selected elements
            elements.forEach((element) => {
                element.style.removeProperty("--framer-text-decoration")

                const markElement = document.createElement("mark")
                const spanElement = document.createElement("span")

                // Wrap the element with mark
                element.parentNode.insertBefore(markElement, element)
                markElement.appendChild(element)

                // Wrap the content of the element with span
                while (element.firstChild) {
                    spanElement.appendChild(element.firstChild)
                }

                element.appendChild(spanElement)
                setIsVisible(true)
            })

            const handle = (entries) => {
                entries.forEach((entry) => {
                    const highlightedValue =
                        entry.target.style.getPropertyValue("--highlighted")
                    console.log("handle")
                    if (!highlightedValue || parseInt(highlightedValue) === 0) {
                        entry.target.style.setProperty(
                            "--highlighted",
                            entry.isIntersecting ? "1" : "0"
                        )
                    }
                })
            }
            const observer = new IntersectionObserver(handle, {
                threshold: 1.0,
            })
            elements.forEach((M) => observer.observe(M))
        }, [props])

        return (
            <>
                <style>{`
.${props.className} mark {
--highlighted: 0;
--highlight: rgba(0, 128, 255, 0.5);
background: transparent;
}

.${props.className} mark span {
background: linear-gradient(120deg, var(--highlight) 50%, transparent 50%) 110% 0 / 200% 100% no-repeat;
background-position: calc((1 - var(--highlighted)) * 110%) 0;
transition: background-position 1s;
color: white;
}
`}</style>
                <Component
                    {...props}
                    style={!isVisible ? { opacity: 0 } : {}}
                />
            </>
        )
    }
}

export function withHighlightColor2(Component): ComponentType {
    return (props: any) => {
        const [isVisible, setIsVisible] = useState(false)

        useEffect(() => {
            const elements = document.querySelectorAll(
                `.${props.className} [style*="--framer-text-decoration: underline"]`
            )

            // Now, let's add a parent <mark> tag to the selected elements
            elements.forEach((element) => {
                element.style.removeProperty("--framer-text-decoration")

                const markElement = document.createElement("mark")
                const spanElement = document.createElement("span")

                // Wrap the element with mark
                element.parentNode.insertBefore(markElement, element)
                markElement.appendChild(element)

                // Wrap the content of the element with span
                while (element.firstChild) {
                    spanElement.appendChild(element.firstChild)
                }

                element.appendChild(spanElement)
                setIsVisible(true)
            })

            const handle = (entries) => {
                entries.forEach((entry) => {
                    const highlightedValue =
                        entry.target.style.getPropertyValue("--highlighted")
                    if (!highlightedValue || parseInt(highlightedValue) === 0) {
                        entry.target.style.setProperty(
                            "--highlighted",
                            entry.isIntersecting ? "1" : "0"
                        )
                    }
                })
            }
            const observer = new IntersectionObserver(handle, {
                threshold: 1.0,
            })
            elements.forEach((M) => observer.observe(M))
        }, [props])

        return (
            <>
                <style>{`
.${props.className} mark {
--highlighted: 0;
--highlight: rgba(255, 195, 0, 0.8);
background: transparent;
}

.${props.className} mark span {
background: linear-gradient(120deg, var(--highlight) 50%, transparent 50%) 110% 0 / 200% 100% no-repeat;
background-position: calc((1 - var(--highlighted)) * 110%) 0;
transition: background-position 1s;
color: black;
}
`}</style>
                <Component
                    {...props}
                    style={!isVisible ? { opacity: 0 } : {}}
                />
            </>
        )
    }
}

export function withHighlightColor3(Component): ComponentType {
    return (props: any) => {
        const [isVisible, setIsVisible] = useState(false)

        useEffect(() => {
            const elements = document.querySelectorAll(
                `.${props.className} [style*="--framer-text-decoration: underline"]`
            )

            // Now, let's add a parent <mark> tag to the selected elements
            elements.forEach((element) => {
                element.style.removeProperty("--framer-text-decoration")

                const markElement = document.createElement("mark")
                const spanElement = document.createElement("span")

                // Wrap the element with mark
                element.parentNode.insertBefore(markElement, element)
                markElement.appendChild(element)

                // Wrap the content of the element with span
                while (element.firstChild) {
                    spanElement.appendChild(element.firstChild)
                }

                element.appendChild(spanElement)
                setIsVisible(true)
            })

            const handle = (entries) => {
                entries.forEach((entry) => {
                    const highlightedValue =
                        entry.target.style.getPropertyValue("--highlighted")
                    if (!highlightedValue || parseInt(highlightedValue) === 0) {
                        entry.target.style.setProperty(
                            "--highlighted",
                            entry.isIntersecting ? "1" : "0"
                        )
                    }
                })
            }
            const observer = new IntersectionObserver(handle, {
                threshold: 1.0,
            })
            elements.forEach((M) => observer.observe(M))
        }, [props])

        return (
            <>
                <style>{`
.${props.className} mark {
--highlighted: 0;
--highlight: rgba(140, 0, 255, 0.5);
background: transparent;
}

.${props.className} mark span {
background: linear-gradient(120deg, var(--highlight) 50%, transparent 50%) 110% 0 / 200% 100% no-repeat;
background-position: calc((1 - var(--highlighted)) * 110%) 0;
transition: background-position 1s;
color: white;
}
`}</style>
                <Component
                    {...props}
                    style={!isVisible ? { opacity: 0 } : {}}
                />
            </>
        )
    }
}

Free Framer Course

Learn how to create stunning websites with ease by learning the fundamentals of Framer.

Free
Framer Course

Learn how to create stunning websites with ease by learning the fundamentals of Framer.

Free Framer Course

Learn how to create stunning websites with ease by learning the fundamentals of Framer.