Bohdan Karpliak

Product designer

Tips & tricks

Coloring individual words in Framer text with variables

Framer can’t color single words in a text layer once a variable is applied. A code override built with Claude fixes that.


Turns out Framer doesn’t let you color individual words inside a text layer once it has a variable applied to it. No built-in way around it.

So I asked Claude to help me build a code override for it. A reusable component that splits a string into multiple parts, each with its own font and color, all editable straight from the Style panel like normal props.

One text block inside the component, multiple colors, no stacking separate text layers just to highlight a word.

Here’s the code. In Framer, create a new code file, paste it in, and drop the RichText component onto the canvas. Each part gets its own text, font and color controls.

jsx
import { addPropertyControls, ControlType } from "framer"

export default function RichText(props) {
    const {
        part1Text,
        part1Font,
        part1Color,
        part2Text,
        part2Font,
        part2Color,
        part3Text,
        part3Font,
        part3Color,
        part4Text,
        part4Font,
        part4Color,
    } = props

    return (
        <div>
            <span style={{ ...part1Font, color: part1Color }}>{part1Text}</span>
            <span style={{ ...part2Font, color: part2Color }}>{part2Text}</span>
            <span style={{ ...part3Font, color: part3Color }}>{part3Text}</span>
            <span style={{ ...part4Font, color: part4Color }}>{part4Text}</span>
        </div>
    )
}

addPropertyControls(RichText, {
    part1Text: {
        type: ControlType.String,
        title: "Part 1 text",
        displayTextArea: true,
        defaultValue: "Senior designers only. ",
    },
    part1Font: {
        type: ControlType.Font,
        title: "Part 1 font",
        controls: "extended",
        defaultValue: { fontSize: 32, variant: "Bold", lineHeight: 1.3 },
    },
    part1Color: {
        type: ControlType.Color,
        title: "Part 1 color",
        defaultValue: "#111111",
    },

    part2Text: {
        type: ControlType.String,
        title: "Part 2 text",
        displayTextArea: true,
        defaultValue:
            "Which means higher quality, faster execution, and better outcomes ",
    },
    part2Font: {
        type: ControlType.Font,
        title: "Part 2 font",
        controls: "extended",
        defaultValue: { fontSize: 32, variant: "Regular", lineHeight: 1.3 },
    },
    part2Color: {
        type: ControlType.Color,
        title: "Part 2 color",
        defaultValue: "#9CA3AF",
    },

    part3Text: {
        type: ControlType.String,
        title: "Part 3 text",
        displayTextArea: true,
        defaultValue: "from day one.",
    },
    part3Font: {
        type: ControlType.Font,
        title: "Part 3 font",
        controls: "extended",
        defaultValue: { fontSize: 32, variant: "Regular", lineHeight: 1.3 },
    },
    part3Color: {
        type: ControlType.Color,
        title: "Part 3 color",
        defaultValue: "#9CA3AF",
    },

    part4Text: {
        type: ControlType.String,
        title: "Part 4 text",
        displayTextArea: true,
        defaultValue: "",
    },
    part4Font: {
        type: ControlType.Font,
        title: "Part 4 font",
        controls: "extended",
        defaultValue: { fontSize: 32, variant: "Regular", lineHeight: 1.3 },
    },
    part4Color: {
        type: ControlType.Color,
        title: "Part 4 color",
        defaultValue: "#9CA3AF",
    },
})

Originally posted on X