Skip to main content

on

Registers an callback that will be called when an event happens in the editor. Current supported events are:

  • The selection on the current page changed.
  • The current page changed.
  • An object from outside Figma is dropped onto the canvas
  • The plugin has started running.
  • The plugin closed.
  • The plugin has started running.
  • The timer has started running.
  • The timer has paused.
  • The timer has stopped.
  • The timer is done.
  • The timer has resumed.

Signature

on(type: ArgFreeEventType, callback: () => void): void

on(type: 'run', callback: (event: RunEvent) => void): void

on(type: 'drop', callback: (event: DropEvent) => boolean): void

Parameters

type

A string identifying the type of event that the callback will be called on.

This is either an ArgFreeEventType, run, or drop. The run event callback will be passed a RunEvent. The drop event callback will be passed a DropEvent.

type ArgFreeEventType =
"selectionchange" |
"currentpagechange" |
"close" |
"timerstart" |
"timerstop" |
"timerpause" |
"timerresume" |
"timeradjust" |
"timerdone"

callback

A function that will be called when the event happens. If type is 'run', then this function will be passed a RunEvent. If type is 'drop', then this function will be passed a DropEvent. Otherwise nothing will be passed in.

Remarks

This API tries to match Node.js conventions around similar .on APIs.

It's important to understand that the .on API runs the callbacks asynchronously. For example:

figma.on("selectionchange", () => { console.log("changed") })
console.log("before")
figma.currentPage.selection = []
console.log("after")

// Output:
// "before"
// "after"
// "changed"

The asynchronous nature of these APIs have a few other implications.

The callback will not necessarily be called each time the event happens. For example, this will only trigger the event once:

figma.currentPage.selection = [figma.createRectangle()]
figma.currentPage.selection = [figma.createFrame()]

Nor will the ordering of the event trigger and event registration affect whether the callback is called.

figma.currentPage.selection = [figma.createFrame()]
figma.on("selectionchange", () => { "this will get called!" })

Available event types

"currentpagechange"

This event will trigger when the user navigates to a different page, or when the plugin changes the value of figma.currentPage.

"selectionchange"

This event will trigger when the selection of the current page changes. This can happen:

  • By user action.
  • Due to plugin code.
  • When the current page changes (a "currentpagechange" event always triggers a "selectionchange" event).
  • When a selected node is deleted.
  • When a selected node becomes the child of another selected node (in which case it is considered indirectly selected, and is no longer in figma.currentPage.selection)

Note also that changing the selection via the plugin API, then changing it back to its previous value immediately still triggers the event.

"drop"

This event will trigger when objects outside Figma (such as elements from other browser windows, or files from the local filesystem) are dropped onto the canvas.

It can also be triggered by a special pluginDrop message sent from the UI. See the Triggering drop events from the UI section for more details.

The callback will be passed a DropEvent with the below interface. It should return false if it wants to handle the particular drop and stop Figma from performing the default drop behavior.

interface DropEvent {
node: BaseNode | SceneNode
x: number
y: number
absoluteX: number
absoluteY: number
items: DropItem[]
files: DropFile[]
dropMetadata?: any
}
  • The node property contains the node where the drop landed. This will sometimes be the page node if the drop didn't land on anything in the canvas, or if target node is locked or cannot be a parent of another node.
  • The x and y properties are coordinates relative to the node drop target
  • The absoluteX and absoluteY properties are absolute canvas coordinates
  • The items property is an array of DropItem objects. You will see multiple objects if a drop contains multiple, non-file data types. If there are no data items, this array will be empty.
  • The files property is an array of dropped files represented as DropFile objects. If no files are present, this array will be empty.
  • The dropMetadata property comes from drop events explicitly triggered by the UI.

Items and files will conform to the below interfaces:

interface DropItem {
type: string // e.g. "text/html", "text/uri-list", etc...
data: string
}

interface DropFile {
name: string // file name
type: string // e.g. "image/png"
getBytesAsync(): Promise<Uint8Array> // get raw file bytes
getTextAsync(): Promise<string> // get text assuming file is UTF8-encoded
}

See the Icon Drag-and-Drop and PNG Crop examples in the figma/plugin-samples repository for plugins that implement this API.

UI Recommendations

When the plugin registers a drop callback, it should give the user instructions with either text in the plugin UI or figma.notify() (if the plugin does not show a UI) telling them what to do.

figma.notify() can be called with the timeout option set to Infinity to make the notification show for as long as the plugin is open.

"close"

This event will trigger when the plugin is about to close, either from a call to figma.closePlugin() or the user closing the plugin via the UI.

This is a good place to run cleanup actions. For example, some plugins add UI elements in the canvas by creating nodes. These UI elements should be deleted when the plugin is closed. Note that you don't need to call figma.closePlugin() again in this function.

You should use this API only if strictly necessary, and run as little code as possible in the callback when doing so. When a user closes a plugin, they expect it to be closed immediately. Having long-running actions in the closing callback prevents the plugin for closing promptly.

This is also not the place to run any asynchronous actions (e.g. register callbacks, using await, etc). The plugin execution environment will be destroyed immediately when all the callbacks have returned, and further callbacks will not be called.

"run"

This event is triggered when a plugin is run. For plugins with parameters, this happens after all parameters have been enter by the user in the quick action UI. For all other plugins this happens immediately after launch.

The callback will be passed a RunEvent that looks like:

interface RunEvent {
parameters?: ParameterValues
command: string
}
  • The parameters property is of type ParameterValues, and contains the value entered for each parameter.
  • The command argument is the same as figma.command, but provided here again for convenience.

Handling the run event is only required for plugins with parameters. For all plugins it can still be a convenient spot to put your top level code, since it is called on every plugin run.

"timerstart"

This event will trigger when somebody starts a timer in the document. This can happen either by a user (either the current user or a multiplayer user) starting the timer from the UI, or triggered by plugin code. To inspect the current state of the timer when this event fires, use the figma.timer interface. For example:

figma.on("timerstart", () => console.log(figma.timer.remaining))
figma.timer.start(300)

// Output:
// 300

"timerpause"

Triggered when a timer that is running is paused.

"timerstop"

Triggered when the timer is stopped.

"timerdone"

Triggered when the timer is running and reaches 0 time remaining.

"timerresume"

Triggered when a timer that is paused is resumed.

"timeradjust"

Triggered when the total time on the timer changes. From the UI, it is only possible to add time to the timer. However, plugin code can both add and remove time from a running timer.