Skip to main content
Solved

How to Assign Component Property to a Text Node within Variants

  • August 12, 2024
  • 2 replies
  • 119 views

Haroon_Chelsea

Hello everyone,

I am developing a Figma plugin where I have created a ComponentSet with two variants. Each variant has a state and a heading property. I want to dynamically assign the heading property to a text node within each variant.

Here is the simplified code for creating the ComponentSet:

figma.showUI(__html__, {
  height: 200,
  width: 400,
});

figma.ui.onmessage = async (msg) => {
  if (msg.type === 'create-input-field') {
    await figma.loadFontAsync({ family: 'Inter', style: 'Regular' });
    // Create variants for the component
    const defaultComponent = createComponentWithFrame('State=Default');
    const filledComponent = createComponentWithFrame('State=Filled');
    // Create a component set and add the components as variants
    const componentSet = figma.combineAsVariants([defaultComponent, filledComponent], figma.currentPage);
    componentSet.name = 'My Component Set';
    componentSet.resizeWithoutConstraints(1200, componentSet.height);
    componentSet.layoutMode = 'HORIZONTAL';
    componentSet.counterAxisSizingMode = 'AUTO';
    componentSet.primaryAxisSizingMode = 'AUTO';
    componentSet.paddingTop = 20;
    componentSet.paddingBottom = 20;
    componentSet.paddingLeft = 20;
    componentSet.paddingRight = 20;
    componentSet.itemSpacing = 18;
    componentSet.fills = [];
    componentSet.cornerRadius = 5;
    componentSet.strokes = [{ type: 'SOLID', color: { r: 0.592, g: 0.278, b: 1.0 } }]; // #9747ff
    componentSet.strokeWeight = 1;
    componentSet.dashPattern = [10, 5];
    componentSet.strokeAlign = 'INSIDE';
    componentSet.strokeJoin = 'MITER';
    componentSet.strokeMiterLimit = 16;
    componentSet.clipsContent = true;

    // Position the component set on the canvas
    componentSet.x = figma.viewport.center.x - componentSet.width / 2;
    componentSet.y = figma.viewport.center.y - componentSet.height / 2;
  }
};

const createComponentWithFrame = (variant: string): ComponentNode => {
  let color: Paint[] = [{ type: 'SOLID', color: { r: 0.592, g: 0.278, b: 1.0 } }];
  switch (variant) {
    case 'State=Filled':
      color = [{ type: 'SOLID', color: { r: 0.9, g: 0.9, b: 0.9 } }];
      break;
    default:
      color = [{ type: 'SOLID', color: { r: 0.592, g: 0.278, b: 1.0 } }];
      break;
  }

  const component = figma.createComponent();
  component.name = variant;
  component.layoutMode = 'VERTICAL';
  component.fills = color;
  component.resizeWithoutConstraints(252, component.height);

  component.addComponentProperty('Heading', 'TEXT', '');
  setupAutoLayoutAndText(component);

  return component;
};

const setupAutoLayoutAndText = (node: BaseFrameMixin): void => {
  node.layoutMode = 'VERTICAL';
  node.primaryAxisSizingMode = 'AUTO';
  node.counterAxisSizingMode = 'AUTO';
  node.paddingTop = 0;
  node.paddingBottom = 0;
  node.paddingLeft = 0;
  node.paddingRight = 0;
  node.itemSpacing = 4;

  const label = figma.createText();
  label.characters = 'Label';
  label.fontName = { family: 'Inter', style: 'Regular' };
  label.lineHeight = {
    value: 23,
    unit: 'PIXELS',
  };
  label.letterSpacing = { value: 0, unit: 'PERCENT' };
  label.textAlignHorizontal = 'LEFT';
  label.textAlignVertical = 'BOTTOM';
  label.fontSize = 14;
  label.name = 'Label';

  const labelContainer = figma.createFrame();
  const childContainer = figma.createFrame();

  labelContainer.counterAxisAlignItems = 'CENTER';
  labelContainer.counterAxisSizingMode = 'AUTO';
  labelContainer.primaryAxisAlignItems = 'MIN';
  labelContainer.primaryAxisSizingMode = 'FIXED';
  labelContainer.fills = [];
  labelContainer.strokes = [];
  labelContainer.paddingTop = 0;
  labelContainer.paddingBottom = 0;
  labelContainer.paddingLeft = 0;
  labelContainer.paddingRight = 0;
  labelContainer.itemSpacing = 4;
  labelContainer.clipsContent = false;
  labelContainer.layoutAlign = 'STRETCH';
  labelContainer.layoutGrow = 0;
  labelContainer.layoutMode = 'HORIZONTAL';
  labelContainer.layoutGrids = [];
  labelContainer.layoutPositioning = 'AUTO';
  labelContainer.appendChild(label);

  node.appendChild(labelContainer);
  node.appendChild(childContainer);
};


I am looking to understand how I can link the heading property to the text node so that changes to the property reflect in the text content.


Any guidance or examples on how to achieve this would be greatly appreciated.

Thank you!

Best answer by tank666

figma.com
View original

2 replies

tank666
  • 4857 replies
  • Answer
  • August 12, 2024

Haroon_Chelsea

Hi @tank666 Thank you for your response! I appreciate the guidance on using the componentPropertyReferences property to link the heading property to the text node.

Here’s the updated code snippet that worked for me:


figma.showUI(__html__, {
  height: 200,
  width: 400,
});

figma.ui.onmessage = async (msg) => {
  if (msg.type === 'create-input-field') {
    await figma.loadFontAsync({ family: 'Inter', style: 'Regular' });
    // Create variants for the component
    const defaultComponent = createComponentWithFrame('State=Default');
    const filledComponent = createComponentWithFrame('State=Filled');
    // Create a component set and add the components as variants
    const componentSet = figma.combineAsVariants([defaultComponent, filledComponent], figma.currentPage);
    componentSet.name = 'My Component Set';
    componentSet.resizeWithoutConstraints(1200, componentSet.height);
    componentSet.layoutMode = 'HORIZONTAL';
    componentSet.counterAxisSizingMode = 'AUTO';
    componentSet.primaryAxisSizingMode = 'AUTO';
    componentSet.paddingTop = 20;
    componentSet.paddingBottom = 20;
    componentSet.paddingLeft = 20;
    componentSet.paddingRight = 20;
    componentSet.itemSpacing = 18;
    componentSet.fills = [];
    componentSet.cornerRadius = 5;
    componentSet.strokes = [{ type: 'SOLID', color: { r: 0.592, g: 0.278, b: 1.0 } }]; // #9747ff
    componentSet.strokeWeight = 1;
    componentSet.dashPattern = [10, 5];
    componentSet.strokeAlign = 'INSIDE';
    componentSet.strokeJoin = 'MITER';
    componentSet.strokeMiterLimit = 16;
    componentSet.clipsContent = true;

    // Position the component set on the canvas
    componentSet.x = figma.viewport.center.x - componentSet.width / 2;
    componentSet.y = figma.viewport.center.y - componentSet.height / 2;
  }
};

const createComponentWithFrame = (variant: string): ComponentNode => {
  let color: Paint[] = [{ type: 'SOLID', color: { r: 0.592, g: 0.278, b: 1.0 } }];
  switch (variant) {
    case 'State=Filled':
      color = [{ type: 'SOLID', color: { r: 0.9, g: 0.9, b: 0.9 } }];
      break;
    default:
      color = [{ type: 'SOLID', color: { r: 0.592, g: 0.278, b: 1.0 } }];
      break;
  }

  const component = figma.createComponent();
  component.name = variant;
  component.layoutMode = 'VERTICAL';
  component.fills = color;
  component.resizeWithoutConstraints(252, component.height);

  const headingProperty = component.addComponentProperty('Heading', 'TEXT', '');
  setupAutoLayoutAndText(component, headingProperty);

  return component;
};

const setupAutoLayoutAndText = (node: BaseFrameMixin, headingProperty: string): void => {
  node.layoutMode = 'VERTICAL';
  node.primaryAxisSizingMode = 'AUTO';
  node.counterAxisSizingMode = 'AUTO';
  node.paddingTop = 0;
  node.paddingBottom = 0;
  node.paddingLeft = 0;
  node.paddingRight = 0;
  node.itemSpacing = 4;

  const label = figma.createText();
  label.characters = 'Label';
  label.fontName = { family: 'Inter', style: 'Regular' };
  label.lineHeight = {
    value: 23,
    unit: 'PIXELS',
  };
  label.letterSpacing = { value: 0, unit: 'PERCENT' };
  label.textAlignHorizontal = 'LEFT';
  label.textAlignVertical = 'BOTTOM';
  label.fontSize = 14;
  label.name = 'Label';

  const labelContainer = figma.createFrame();
  const childContainer = figma.createFrame();

  labelContainer.counterAxisAlignItems = 'CENTER';
  labelContainer.counterAxisSizingMode = 'AUTO';
  labelContainer.primaryAxisAlignItems = 'MIN';
  labelContainer.primaryAxisSizingMode = 'FIXED';
  labelContainer.fills = [];
  labelContainer.strokes = [];
  labelContainer.paddingTop = 0;
  labelContainer.paddingBottom = 0;
  labelContainer.paddingLeft = 0;
  labelContainer.paddingRight = 0;
  labelContainer.itemSpacing = 4;
  labelContainer.clipsContent = false;
  labelContainer.layoutAlign = 'STRETCH';
  labelContainer.layoutGrow = 0;
  labelContainer.layoutMode = 'HORIZONTAL';
  labelContainer.layoutGrids = [];
  labelContainer.layoutPositioning = 'AUTO';
  labelContainer.appendChild(label);

  node.appendChild(labelContainer);
  label.componentPropertyReferences = { characters: headingProperty };
  node.appendChild(childContainer);
};

Thank you again for your help!


Reply


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