Skip to main content
Question

How to use setBoundVariableForPaint


Pavel_Kiselev

I would appreciate some guidance on figma.variables. setBoundVariableForPaint method.

figma.com

I would like to run a simple script to bind a variable to the existing style. This is what I tried

// get a style ref
let style = figma.getLocalPaintStyles()[0];
// get a var ref
let variable = figma.variables.getVariableById("VariableID:1:53");
// bind?
figma.variables.setBoundVariableForPaint(style.paints[0], 'color', variable);

It returns a solid paint indeed, however, it has no effect on a given style. Confusing…

This topic has been closed for comments

12 replies

Pavel_Kiselev
  • Author
  • Power Member
  • 438 replies
  • June 27, 2023

Alright, seem like it does not change the pain itself but returns a new one.

const styles = figma.getLocalPaintStyles();
const variables = figma.variables.getLocalVariables();

let getStyleByName = (name) => {
    return styles.find((style) => style.name === name);
};

variables.forEach(variable => {
    const name = variable.name;
    let style = getStyleByName(name);
    if(style) {
        let newPaints = style.paints.map(paint => {
            return figma.variables.setBoundVariableForPaint(paint, 'color', variable);
        });
        style.paints = newPaints;
    }
});

Jay_Ransijn

Very confusing API indeed. I think there’s an issue with your code, afaik you can’t update paints of existing styles, which has been a shortcoming I haven’t been able to overcome and I think is not possible (no updateLocalStyles for instance only create). The line style.paints = newPaints; shouldn’t work I believe, although confusingly it doesn’t give a warning when using TypeScript, the type is typed as readonly Paint[].

Update:
To my surprise it’s possible to update paints by reassigning, I wish I tried this approach before! I was able to create the styles to variables functionality similar to Styles-to-Variables-Converter.

My code is as follows that might benefit others:

const localPaintStyles = figma
    .getLocalPaintStyles()
    .filter((style) => style.paints[0].type === "SOLID");

const date = new Date();
const collectionName = `Colors (imported at ${date.toLocaleString()})`;
const collection = figma.variables.createVariableCollection(collectionName);
collection.name = collectionName;

for (const paintStyle of localPaintStyles) {
    // Create variable.
    const colorVariable = figma.variables.createVariable(
        paintStyle.name,
        collection.id,
        "COLOR"
    );

  	// This only works for single color per style.
    const solidPaint = paintStyle.paints[0] as SolidPaint

    // Set the current color to the first mode.
    colorVariable.setValueForMode(
        collection.modes[0].modeId,
        solidPaint.color
    );

    // Also port the description of the paint style.
    colorVariable.description = paintStyle.description

    // Update the color style to use the variable.
    const newPaint = figma.variables.setBoundVariableForPaint(
        solidPaint,
        "color",
        colorVariable
    );

    // Change the paint on the existing style to use the variable.
    paintStyle.paints = [newPaint];
}

Pavel_Kiselev
  • Author
  • Power Member
  • 438 replies
  • June 29, 2023

Well, shortly after my discovery I found this - https://www.figma.com/plugin-docs/working-with-variables/#example-binding-a-variable-to-a-node-or-style

Official code that reassign paints, yay! I swear it wasn’t there before 😉


tank666
  • 4871 replies
  • June 29, 2023

lucas.smith

Seems using

const colorVar = {
    "type": "VARIABLE_ALIAS",
    "id": "VariableID:dc7eae0065a4fa2e06bdb4ffa9bf4a755a8232d3/3:77"
  }

const fillsCopy = clone(node.fills)
fillsCopy[0] = figma.variables.setBoundVariableForPaint(fillsCopy[0], 'color', colorVar)
node.fills = fillsCopy

throws a ts error for colorVar in setBoundVariableForPaint. Any ideas as to why? The Variable is getting fetched from a variable file that is available to the file 😕


Pavel_Kiselev
  • Author
  • Power Member
  • 438 replies
  • August 17, 2023

Your colorVar isn’t variable yet, it’s an object that you can feed into setValueForMode(modeId: string, newValue: [VariableValue])

And then do as usual


lucas.smith

I’m trying to apply these new color variables by key when their name matches a currently used fillStyle.

So I want to push something like this in that colorVar property?

{
  key: "0cf002c6d23cdefe1209c2caa26a954ca94081ba"
  name: "brand/background"
  resolvedType: "COLOR"
}

lucas.smith

Ultimately I’m trying to swap FillStyles with Color Variables is the goal. Seems like setBoundVariableForPaint is the obvious way to do that but I’m not 100% clear on the types of the properties in that method. Like what goes is the third param expecting here?

paintsCopy[0] = figma.variables.setBoundVariableForPaint(paintsCopy[0], 'color', colorVariable)

Pavel_Kiselev
  • Author
  • Power Member
  • 438 replies
  • August 17, 2023

It takes time to figure out, I found out that reading the docs, digesting and fair bit of experiments to work well 😎


Pavel_Kiselev
  • Author
  • Power Member
  • 438 replies
  • August 18, 2023

There is a code sample above that does exactly that - How to use setBoundVariableForPaint - #2 by Pavel_Kiselev

It loops through local variables, checks local colour styles and bind them together whenever name matches


Pavel_Kiselev
  • Author
  • Power Member
  • 438 replies
  • August 18, 2023

And another one that goes other way around - it takes local colour styles and makes variables out of them


tinaciousdesign

This is great! I had been creating blank colour variables, turns out I was missing setValueForMode. Thanks for this!


Cookie policy

We use cookies to enhance and personalize your experience. If you accept you agree to our full cookie policy. Learn more about our cookies.

 
Cookie settings