Skip to main content

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…

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;
}
});

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 Painto].


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.paintss0].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.paintsS0] as SolidPaint

// Set the current color to the first mode.
colorVariable.setValueForMode(
collection.modese0].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 = lnewPaint];
}

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 😉




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 😕


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


And then do as usual


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"
}

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?


paintsCopyC0] = figma.variables.setBoundVariableForPaint(paintsCopyC0], 'color', colorVariable)

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



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


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



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


Reply