Version 1, Update 88
New
- DocumentNode.findWidgetNodesByWidgetId was previously undocumented, and has since been added to the documentation and type definitions.
Over the past few months, Figma has been rolling out dynamic page loading, which allows documents to load pages on demand, rather than all at once. For backward compatibility, Figma loads all pages in the document before attempting to run an extension (a plugin or widget), which can sometimes result in a noticeable delay.
We're pleased to announce a new set of APIs that allow extensions to work safely with dynamic page loading, and avoid triggering the loading delay. Alongside these new APIs, we are deprecating several existing methods and properties. This will help to ensure that new extensions will be compatible with dynamic page loading by default.
To mark an extension as compatible with dynamic page loading, add "documentAccess": "dynamic-page" to manifest.json. Extensions with this manifest field will not encounter loading delays, but they'll be unable to access any of the deprecated methods and properties listed below. New extensions will include this manifest field by default.
To learn more about updating your extension, see our comprehensive migration guide. For TypeScript users, we've also provided an ESLint plugin that can help identify and automatically fix callsites that need to be updated.
As of February 21st, dynamic page loading APIs are generally available (GA). You can update existing extensions and create new extensions using the dynamic page loading APIs and the manifest field "documentAccess": "dynamic-page".
Starting in April, the manifest field "documentAccess": "dynamic-page" will be required for all widgets, and all new plugins.
Several methods and properties have been deprecated in favor of async replacements:
figma.getFileThumbnailNodeAsync() instead of figma.getFileThumbnailNode().figma.getLocalEffectStylesAsync() instead of figma.getLocalEffectStyles().figma.getLocalGridStylesAsync() instead of figma.getLocalGridStyles().figma.getLocalPaintStylesAsync() instead of figma.getLocalPaintStyles().figma.getLocalTextStylesAsync() instead of figma.getLocalTextStyles().figma.getNodeByIdAsync() instead of figma.getNodeById().figma.getStyleByIdAsync() instead of figma.getStyleById().figma.variables.getLocalVariableCollectionsAsync() instead of figma.variables.getLocalVariableCollections().figma.variables.getLocalVariablesAsync() instead of figma.variables.getLocalVariables().figma.variables.getVariableByIdAsync() instead of figma.variables.getVariableById().figma.variables.getVariableCollectionByIdAsync() instead of figma.variables.getVariableCollectionById().setRangeFillStyleIdAsync() instead of setRangeFillStyleId().setRangeTextStyleIdAsync() instead of setRangeTextStyleId().In some specific cases, reading node properties has been deprecated in favor of an async getter:
ComponentNode.getInstancesAsync() instead of ComponentNode.instances.getStyleConsumersAsync() instead of the consumers.InstanceNode.getMainComponentAsync() instead of InstanceNode.mainComponent.In some specific cases, assigning values directly to node properties has been deprecated in favor of an async setter:
figma.setCurrentPageAsync() instead of assigning to figma.currentPage.setEffectStyleIdAsync() instead of assigning to effectStyleId.setFillStyleIdAsync() instead of assigning to backgroundStyleId.setFillStyleIdAsync() instead of assigning to fillStyleId.setGridStyleIdAsync() instead of assigning to gridStyleId.setReactionsAsync() instead of assigning to reactions.setStrokeStyleIdAsync() instead of assigning to strokeStyleId.setVectorNetworkAsync() instead of assigning to vectorNetwork.TextNode.setTextStyleIdAsync() instead of assigning to TextNode.textStyleId.If an extension's manifest contains "documentAccess": "dynamic-page", accessing any of the deprecated items listed above will throw an exception.
If an extension's manifest contains "documentAccess": "dynamic-page", calling any of the following methods will throw an exception unless you first call figma.loadAllPagesAsync():
DocumentNode.findAll()DocumentNode.findAllWithCriteria()DocumentNode.findOne()DocumentNode.findWidgetNodesByWidgetId()For the methods listed below, passing a string ID is now deprecated in favor of passing objects that the IDs refer to. If an extension's manifest contains "documentAccess": "dynamic-page", passing an ID will throw an exception.
figma.variables.createVariable() - Pass a VariableCollection object instead of a collection ID.clearExplicitVariableModeForCollection() (present on multiple node types) - Pass a VariableCollection object instead of a collection ID.setExplicitVariableModeForCollection() (present on multiple node types) - Pass a VariableCollection object instead of a collection ID.setBoundVariable() (present on multiple node types) - Pass a Variable object instead of a variable ID.If an extension's manifest contains "documentAccess": "dynamic-page", some properties and methods of PageNode will throw an exception unless you explicitly load the page first using PageNode.loadAsync(). These include:
"documentAccess": "dynamic-page", the documentchange event will not be available unless you first call figma.loadAllPagesAsync().nodechange and stylechange events, which do not require triggering a full-document load.New:
figma.createComponentFromNode function to create a component from an existing node, preserving all of its properties and children.New:
null is now supported for the variable field in setBoundVariableForPaint, setBoundVariableForEffect, and setBoundVariableForLayoutGrid. Passing in null will detach the bound variables.
For plugins that can run in VSCode, we now recommend replacing alert() and confirm() dialogs in the plugin UI with custom UI, since VS Code blocks native dialogs.
The Working in Dev Mode page is updated accordingly.
Updates:
type property to go from an instance of BaseStyle to a child style type.boundVariables keyed by style type (effects or layoutGrids).This update includes changes to the Variables API to support binding variables to effects, layout grids, stroke weights, and layer opacity. We are also releasing support to run Dev Mode plugins in the Figma for VS Code extension.
Changes to the Variables API:
FLOAT and COLOR variables can be bound to Effects via the setBoundVariablesForEffect() helper.FLOAT variables can be bound to LayoutGrids via the setBoundVariablesForLayoutGrid() helper.FLOAT variables can be bound to layer opacity, stroke weights, and individual stroke weights.Dev Mode plugins can now run in the Figma for VS Code extension with some minor manifest and code changes:
vscode capabilityFixes:
fillGeometry and strokeGeometry properties are correctly marked as readonlyNew:
NEGATE as a Prototyping ExpressionFunction type!New:
variableIds are now returned in a similar order to the Figma Design UI. See VariableCollection#variableIdstextRangeFills to the boundVariables structure. This will be populated on text nodes which have color variables bound to substrings.The Plugin API runtime has been updated to ensure proper usage of figma.showUI.
It is unsafe to call figma.showUI within an event handler for the figma.codegen.on("generate") event. In development, figma.showUI will now throw an error when called as a result of a figma.codegen.on("generate")
If you need to trigger code inside an iframe as the result of a generate callback, you should instead move the call to showUI outside of the event handler and use figma.ui.postMessage to communicate with the iframe from within the callback. This will ensure that your plugin can to handle concurrent generate events. Here's a code example for how to do this.