Text Color Animation Code Component

Copy component

Copy component

Text Color Animation Code Component

Copy component

Component

Text Color Animation Code Component

This is a code component for creating a text color animation in Framer. This effect looks stunning on all websites and could be a fantastic addition to yours too. However, make sure not to overdo it.

This effect was inspired by the Minhpham website.

image of Nandi Muzsik

Created by

Text Color Animation Code Component
Text Color Animation Code Component
Text Color Animation Code Component

About the resource

Fully customizable through component properties, here's what you can do:

  • Set text.

  • Adjust the font size.

  • Alter text colors one and two.

  • Choose your font family and weight.

  • Set the animation duration.

  • Apply a delay, if needed.

  • Toggle replaying.

The animation will always play when the component comes into the viewport. If you want, you can delay this animation.

Just remember, the text stays on a single line. If you need multiple lines, you'll have to use separate components for each line of text.

Source code

If you want to take a look at how such a code component is built in Framer, feel free to copy this code from below and dig into it.

About the resource

Fully customizable through component properties, here's what you can do:

  • Set text.

  • Adjust the font size.

  • Alter text colors one and two.

  • Choose your font family and weight.

  • Set the animation duration.

  • Apply a delay, if needed.

  • Toggle replaying.

The animation will always play when the component comes into the viewport. If you want, you can delay this animation.

Just remember, the text stays on a single line. If you need multiple lines, you'll have to use separate components for each line of text.

Source code

If you want to take a look at how such a code component is built in Framer, feel free to copy this code from below and dig into it.

About the resource

Fully customizable through component properties, here's what you can do:

  • Set text.

  • Adjust the font size.

  • Alter text colors one and two.

  • Choose your font family and weight.

  • Set the animation duration.

  • Apply a delay, if needed.

  • Toggle replaying.

The animation will always play when the component comes into the viewport. If you want, you can delay this animation.

Just remember, the text stays on a single line. If you need multiple lines, you'll have to use separate components for each line of text.

Source code

If you want to take a look at how such a code component is built in Framer, feel free to copy this code from below and dig into it.

import React, { useEffect, useRef } from "react"
import { motion, useAnimation } from "framer-motion"
import { addPropertyControls, ControlType } from "framer"

export default function TextColorAnimation({
    text,
    fontSize,
    fontFamily,
    fontWeight,
    textAlign,
    color01,
    color02,
    Duration,
    delay,
    replays,
}) {
    const controls = useAnimation()
    const textRef = useRef()

    useEffect(() => {
        const observer = new IntersectionObserver(async ([entry]) => {
            if (entry.isIntersecting) {
                await new Promise((resolve) =>
                    setTimeout(resolve, delay * 1000)
                ) // delay before animation starts
                controls.start("visible")
            } else if (!entry.isIntersecting && replays) {
                controls.start("hidden")
            }
        })

        observer.observe(textRef.current)

        return () => observer.disconnect()
    }, [Duration, controls, color01, delay, replays])

    return (
        <div
            style={{
                fontSize: `${fontSize}px`,
                fontFamily: fontFamily,
                fontWeight: fontWeight,
                width: "100%",
                whiteSpace: "nowrap",
                color: color01,
                textAlign: textAlign,
            }}
            ref={textRef}
        >
            <span style={{ position: "relative", display: "inline-block" }}>
                {text}
                <motion.span
                    style={{
                        position: "absolute",
                        overflow: "hidden",
                        whiteSpace: "nowrap",
                        color: color02,
                        top: 0,
                        left: 0,
                        width: "0%",
                    }}
                    animate={controls}
                    initial={{ width: "0%" }}
                    variants={{
                        visible: { width: "100%" },
                        hidden: { width: "0%" },
                    }}
                    transition={{ duration: Duration }}
                >
                    {text}
                </motion.span>
            </span>
        </div>
    )
}

addPropertyControls(TextColorAnimation, {
    text: { type: ControlType.String, defaultValue: "Hello, World!" },
    fontSize: {
        type: ControlType.Number,
        defaultValue: 16,
        min: 1,
        max: 200,
        unit: "px",
    },
    fontFamily: { type: ControlType.String, defaultValue: "Arial" },
    fontWeight: {
        type: ControlType.Enum,
        defaultValue: "400",
        options: [
            "100",
            "200",
            "300",
            "400",
            "500",
            "600",
            "700",
            "800",
            "900",
        ],
    },
    textAlign: {
        title: "Text Align",
        type: ControlType.Enum,
        displaySegmentedControl: true,
        optionTitles: ["Left", "Center", "Right"],
        options: ["left", "center", "right"],
    },
    color01: {
        title: "Color 01",
        type: ControlType.Color,
        defaultValue: "#333",
    },
    color02: {
        title: "Color 02",
        type: ControlType.Color,
        defaultValue: "#fff",
    },
    Duration: {
        type: ControlType.Number,
        defaultValue: 1.0,
        min: 0.1,
        max: 10.0,
        step: 0.1,
    },
    delay: {
        title: "Delay",
        type: ControlType.Number,
        defaultValue: 0,
        min: 0,
        max: 10.0,
        step: 0.1,
    },
    replays: {
        title: "Replays",
        type: ControlType.Boolean,
        defaultValue: true,
    },
})
import React, { useEffect, useRef } from "react"
import { motion, useAnimation } from "framer-motion"
import { addPropertyControls, ControlType } from "framer"

export default function TextColorAnimation({
    text,
    fontSize,
    fontFamily,
    fontWeight,
    textAlign,
    color01,
    color02,
    Duration,
    delay,
    replays,
}) {
    const controls = useAnimation()
    const textRef = useRef()

    useEffect(() => {
        const observer = new IntersectionObserver(async ([entry]) => {
            if (entry.isIntersecting) {
                await new Promise((resolve) =>
                    setTimeout(resolve, delay * 1000)
                ) // delay before animation starts
                controls.start("visible")
            } else if (!entry.isIntersecting && replays) {
                controls.start("hidden")
            }
        })

        observer.observe(textRef.current)

        return () => observer.disconnect()
    }, [Duration, controls, color01, delay, replays])

    return (
        <div
            style={{
                fontSize: `${fontSize}px`,
                fontFamily: fontFamily,
                fontWeight: fontWeight,
                width: "100%",
                whiteSpace: "nowrap",
                color: color01,
                textAlign: textAlign,
            }}
            ref={textRef}
        >
            <span style={{ position: "relative", display: "inline-block" }}>
                {text}
                <motion.span
                    style={{
                        position: "absolute",
                        overflow: "hidden",
                        whiteSpace: "nowrap",
                        color: color02,
                        top: 0,
                        left: 0,
                        width: "0%",
                    }}
                    animate={controls}
                    initial={{ width: "0%" }}
                    variants={{
                        visible: { width: "100%" },
                        hidden: { width: "0%" },
                    }}
                    transition={{ duration: Duration }}
                >
                    {text}
                </motion.span>
            </span>
        </div>
    )
}

addPropertyControls(TextColorAnimation, {
    text: { type: ControlType.String, defaultValue: "Hello, World!" },
    fontSize: {
        type: ControlType.Number,
        defaultValue: 16,
        min: 1,
        max: 200,
        unit: "px",
    },
    fontFamily: { type: ControlType.String, defaultValue: "Arial" },
    fontWeight: {
        type: ControlType.Enum,
        defaultValue: "400",
        options: [
            "100",
            "200",
            "300",
            "400",
            "500",
            "600",
            "700",
            "800",
            "900",
        ],
    },
    textAlign: {
        title: "Text Align",
        type: ControlType.Enum,
        displaySegmentedControl: true,
        optionTitles: ["Left", "Center", "Right"],
        options: ["left", "center", "right"],
    },
    color01: {
        title: "Color 01",
        type: ControlType.Color,
        defaultValue: "#333",
    },
    color02: {
        title: "Color 02",
        type: ControlType.Color,
        defaultValue: "#fff",
    },
    Duration: {
        type: ControlType.Number,
        defaultValue: 1.0,
        min: 0.1,
        max: 10.0,
        step: 0.1,
    },
    delay: {
        title: "Delay",
        type: ControlType.Number,
        defaultValue: 0,
        min: 0,
        max: 10.0,
        step: 0.1,
    },
    replays: {
        title: "Replays",
        type: ControlType.Boolean,
        defaultValue: true,
    },
})
import React, { useEffect, useRef } from "react"
import { motion, useAnimation } from "framer-motion"
import { addPropertyControls, ControlType } from "framer"

export default function TextColorAnimation({
    text,
    fontSize,
    fontFamily,
    fontWeight,
    textAlign,
    color01,
    color02,
    Duration,
    delay,
    replays,
}) {
    const controls = useAnimation()
    const textRef = useRef()

    useEffect(() => {
        const observer = new IntersectionObserver(async ([entry]) => {
            if (entry.isIntersecting) {
                await new Promise((resolve) =>
                    setTimeout(resolve, delay * 1000)
                ) // delay before animation starts
                controls.start("visible")
            } else if (!entry.isIntersecting && replays) {
                controls.start("hidden")
            }
        })

        observer.observe(textRef.current)

        return () => observer.disconnect()
    }, [Duration, controls, color01, delay, replays])

    return (
        <div
            style={{
                fontSize: `${fontSize}px`,
                fontFamily: fontFamily,
                fontWeight: fontWeight,
                width: "100%",
                whiteSpace: "nowrap",
                color: color01,
                textAlign: textAlign,
            }}
            ref={textRef}
        >
            <span style={{ position: "relative", display: "inline-block" }}>
                {text}
                <motion.span
                    style={{
                        position: "absolute",
                        overflow: "hidden",
                        whiteSpace: "nowrap",
                        color: color02,
                        top: 0,
                        left: 0,
                        width: "0%",
                    }}
                    animate={controls}
                    initial={{ width: "0%" }}
                    variants={{
                        visible: { width: "100%" },
                        hidden: { width: "0%" },
                    }}
                    transition={{ duration: Duration }}
                >
                    {text}
                </motion.span>
            </span>
        </div>
    )
}

addPropertyControls(TextColorAnimation, {
    text: { type: ControlType.String, defaultValue: "Hello, World!" },
    fontSize: {
        type: ControlType.Number,
        defaultValue: 16,
        min: 1,
        max: 200,
        unit: "px",
    },
    fontFamily: { type: ControlType.String, defaultValue: "Arial" },
    fontWeight: {
        type: ControlType.Enum,
        defaultValue: "400",
        options: [
            "100",
            "200",
            "300",
            "400",
            "500",
            "600",
            "700",
            "800",
            "900",
        ],
    },
    textAlign: {
        title: "Text Align",
        type: ControlType.Enum,
        displaySegmentedControl: true,
        optionTitles: ["Left", "Center", "Right"],
        options: ["left", "center", "right"],
    },
    color01: {
        title: "Color 01",
        type: ControlType.Color,
        defaultValue: "#333",
    },
    color02: {
        title: "Color 02",
        type: ControlType.Color,
        defaultValue: "#fff",
    },
    Duration: {
        type: ControlType.Number,
        defaultValue: 1.0,
        min: 0.1,
        max: 10.0,
        step: 0.1,
    },
    delay: {
        title: "Delay",
        type: ControlType.Number,
        defaultValue: 0,
        min: 0,
        max: 10.0,
        step: 0.1,
    },
    replays: {
        title: "Replays",
        type: ControlType.Boolean,
        defaultValue: true,
    },
})

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

    SVG Component for Framer

    SVG Component for Framer

    Component

    SVG Component for Framer

    SVG Component for Framer

    Component

    SVG Component for Framer

    SVG Component for Framer

    Component

    Copy Component Button (Copy to Clipboard)

    Copy Component Button (Copy to Clipboard)

    Component

    Copy Component Button (Copy to Clipboard)

    Copy Component Button (Copy to Clipboard)

    Component

    Copy Component Button (Copy to Clipboard)

    Copy Component Button (Copy to Clipboard)

    Component