CtrlK
BlogDocsLog inGet started
Tessl Logo

figma.connect-best-practices

Guidelines for writing Figma Code Connect property mappings. Use this skill when working on Figma Code Connect files, which typically end in .figma.tsx.

Invalid
This skill can't be scored yet
Validation errors are blocking scoring. Review and fix them to unlock Quality, Impact and Security scores. See what needs fixing →
SKILL.md
Quality
Evals
Security

Guidelines for writing Figma Code Connect mappings

Property Mapping Guidelines

  • figma.enum() - For dropdowns/variants
variant: figma.enum('variant', {
  'Figma Display Name': 'codeValue',
  'Primary': 'primary',
  'Secondary': 'secondary',
}),
  • figma.boolean() - For boolean properties
disabled: figma.boolean('disabled'),
loading: figma.boolean('loading'),
  • figma.boolean() for conditional properties\

In some cases, you only want to render a certain prop if it matches some value in Figma. You can do this either by passing a partial mapping object, or setting the value to undefined.

// Don't render the prop if 'Has label' in figma is `false`
figma.boolean('has label', {
  true: figma.string('label'),
  false: undefined,
});
  • figma.string() - For text properties (component properties with text values)
label: figma.string('label'),
  • figma.textContent() - For text layer content (when text is stored in a layer, not a property)

A common pattern in Figma design systems is to override text content directly on instances rather than using component properties. Use figma.textContent() to extract the actual text from a named text layer.

// Extract text from a layer named 'Title'
title: figma.textContent('Title'),

Key difference: Use figma.string() when text is controlled by a Figma component property. Use figma.textContent() when text lives as content in a text layer that designers override directly.

CRITICAL: figma.textContent() only works on actual TEXT layers — never on component instances.

Before using figma.textContent('LayerName'), always call get_metadata on that layer's node ID to verify its type. In the metadata response, the node must appear as a <text> element. If it appears as <instance>, <symbol>, <frame>, or any other non-text type, figma.textContent() will fail at runtime in Figma with a "Layer not found" error even though the layer name is correct.

When the target layer is a component instance (e.g. a reusable text component), use a hardcoded placeholder string instead:

// ❌ Wrong: 'string.label' is a component instance, not a text layer
label: figma.boolean('show label', {
  true: figma.textContent('string.label'),
  false: undefined,
}),

// ✅ Correct: use a placeholder string when the layer is an instance
label: figma.boolean('show label', {
  true: 'Your label here.',
  false: undefined,
}),
  • figma.instance() - For instance-swap properties (component slots)

Use figma.instance() returns the JSX from another figma.connect() call that you can use in the example. This is useful for components that accept a node of another React component as a prop.

In the example below, Button accepts an instance of Icon as the icon prop. We would need to have another call to figma.connect() for the Icon component somewhere in our code connect setup.

figma.connect(Button, 'https://...', {
  props: {
    icon: figma.instance('Icon'),
  },
  example: ({ icon }) => {
    return <Button icon={icon}>Instance prop Example</Button>;
  },
});
  • figma.children() - For child instances by layer name

Use this property mapping when your React component accepts children. figma.children maps a Figma layer name to the children prop.

// Maps child instances that aren't bound to an instance-swap prop
icon: figma.children('IconLayer'),
  • figma.nestedProps() - For accessing properties from child component layers
// Access properties from a nested instance layer named 'Avatar'
avatar: figma.nestedProps('Avatar', {
  size: figma.enum('size', { ... }),
  src: figma.string('src'),
}),
// In example: use avatar.size, avatar.src

Understanding Nested Properties (Important)

In Figma's properties panel, you may see properties with the symbol (e.g., ↳ subtitle). This indicates the property is exposed from a child layer, not defined directly on the parent component.

Why this matters: The Code Connect validation run during figma connect publish has limited coverage. It only validates these prop kinds:

  • figma.boolean(), figma.enum(), figma.string() - validates the property name exists
  • figma.children() - validates the layer name exists

These prop kinds are NOT validated at all:

  • figma.nestedProps() - layer name and inner property mappings are not checked
  • figma.instance() - layer/instance name is not checked
  • figma.textContent() - layer name is not checked

Additionally, validation does not recurse into boolean true/false branch values.

This can result in technically incorrect mappings being published to Figma withoug being caught during validation.

Incorrect approach (will pass validation but fail at runtime):

// ❌ Wrong: 'subtitle' should be a nested property, not a direct component property
subtitle: figma.boolean('show subtitle', {
  true: figma.string('subtitle'),
  false: undefined,
}),

Correct approach using figma.nestedProps():

// ✅ Correct: Use nestedProps to access properties from the child layer
subtitle: figma.boolean('show subtitle', {
  true: figma.nestedProps('subtitle', {
    text: figma.string('subtitle'),
  }),
  false: { text: undefined },
}),
// In example: use subtitle.text

Tip: When in doubt about whether a property is direct or nested, check if it has the symbol in Figma's properties panel. If it does, you likely need figma.nestedProps() or figma.textContent().

Multi-Variant Support

For components with multiple variants in Figma, create separate figma.connect() calls:

// Default variant
figma.connect(ComponentName, 'figma-url', {
  /* props */
});

// Specific variant
figma.connect(ComponentName, 'figma-url', {
  variant: { 'show suffix': true },
  props: {
    /* variant-specific props */
  },
  example: (props) => <ComponentName {...props} />,
});

Use variant-specific connects when child layer names differ across variants.

figma.children('LayerName') only matches layers with that exact name. If different variants use different layer names for the same logical prop (e.g. Button for the single-action variant and ButtonGroup for the multi-action variant), a single figma.children() call will silently produce nothing for the non-matching variants. Split into separate connects with variant: { ... } filters:

// ❌ Wrong: 'ButtonGroup' doesn't exist in the single-action variant
figma.connect(Footer, url, {
  props: { action: figma.children('ButtonGroup') },
  example: ({ action }) => <Footer action={action} />,
});

// ✅ Correct: separate connects for each variant
figma.connect(Footer, url, {
  variant: { '# of actions': '1' },
  props: { action: figma.children('Button') },
  example: ({ action }) => <Footer action={action} />,
});

figma.connect(Footer, url, {
  variant: { '# of actions': '2' },
  props: { action: figma.children('ButtonGroup') },
  example: ({ action }) => <Footer action={action} />,
});

Common Mapping Mistakes

1. Text Content vs Text Properties

Problem: Using figma.string() when the text is a layer name, not a property.

// ❌ Wrong: 'value' is a text layer name, not a property
children: figma.string('value');

// ✅ Correct: Use textContent for text layers
children: figma.textContent('value');

2. Property Values vs Properties

Problem: Treating an enum property value as a separate property.

// ❌ Wrong: 'disabled' might be a value of 'state', not its own property
disabled: figma.boolean('disabled');

// ✅ Correct: Map from the state enum
disabled: figma.enum('state', {
  disabled: true,
  default: false,
  focused: false,
  hovered: false,
  pressed: false,
});

3. Using figma.textContent() on a Component Instance

Problem: figma.textContent() is called with a layer name that belongs to a component instance, not a raw text layer. The mapping appears valid but fails at runtime in Figma with "Layer not found".

How to detect: Call get_metadata on the layer node ID. If the response shows <instance ...> instead of <text ...>, figma.textContent() will not work.

// ❌ Wrong: 'string.label' is a component instance — textContent silently fails
label: figma.boolean('show label', {
  true: figma.textContent('string.label'),
  false: undefined,
}),

// ✅ Correct: use a hardcoded placeholder string
label: figma.boolean('show label', {
  true: 'Your label here.',
  false: undefined,
}),

4. Property Name Formatting

Problem: Property names in Figma often have spaces and must match exactly.

// ❌ Wrong: camelCase doesn't match Figma property name
showStart: figma.boolean('showStart');

// ✅ Correct: Use exact Figma property name with spaces
start: figma.boolean('show start', {
  true: figma.instance('start'),
  false: undefined,
});
Repository
coinbase/cds
Last updated
Created

Is this your skill?

If you maintain this skill, you can claim it as your own. Once claimed, you can manage eval scenarios, bundle related skills, attach documentation or rules, and ensure cross-agent compatibility.