I’m building a Figma plugin and need help with detecting when a frame gets moved around. I want to execute my custom function called UpdateLayout() but only after the user finishes dragging and drops the frame at its new spot.
Right now my code runs every time the selection changes which is not what I want. Here’s what I have:
figma.on('selectionchange', () => {
const currentSelection = figma.currentPage.selection;
currentSelection.forEach(element => {
if (element.type === 'FRAME') {
console.log(`Frame position is now: (${element.x}, ${element.y})`);
UpdateLayout();
}
});
});
This approach doesn’t work because it fires when I select the frame, not when I actually move it. What’s the right way to detect the drop event specifically?
The documentchange approach works well, but heads up - it’ll fire multiple times during a single drag if you’re moving frames fast. I fixed this by combining documentchange with position checking. Cache the frame’s starting coordinates when the event kicks off, then only run UpdateLayout() if the final position moved more than a few pixels from your cached spot. Stops duplicate calls when Figma batches coordinate updates during complex moves. Just remember documentchange catches programmatic position changes too, not just user drags. Keep that in mind if your plugin moves frames automatically somewhere else.
You’re listening to the wrong event. Selection changes don’t track element movement at all. You need the documentchange event - it fires when node properties change, including position coordinates.
Here’s how I solved this in my layout plugin:
figma.on('documentchange', (event) => {
for (const change of event.documentChanges) {
if (change.type === 'PROPERTY_CHANGE' &&
change.node.type === 'FRAME' &&
(change.properties.includes('x') || change.properties.includes('y'))) {
console.log(`Frame moved to: (${change.node.x}, ${change.node.y})`);
UpdateLayout();
}
}
});
This watches for actual property changes on frame nodes and catches x/y coordinate updates. It fires once when you release the drag, not while dragging, so you’ll get exactly what you want.
documentchange is definitely the way to go, but I hit some performance issues when I first used it. Fair warning - it fires constantly during complex operations, so you’ll want to debounce it or UpdateLayout will run way too often. I store the previous frame positions and only run my update function when coordinates actually change by a meaningful amount. Checking if the difference is over 1 pixel helps filter out tiny adjustments from other operations. Also heads up - documentchange fires for any property change on frames, not just position, so you’ll catch resize events too if that matters. Works great once you dial it in though. Way more reliable than messing with selection events.
Had this exact problem last week! Try adding a short timeout after documentchange fires - prevents it from triggering while you’re still dragging. setTimeout(() => UpdateLayout(), 100) does the trick. Also check if the frame moved far enough to matter, otherwise you’ll catch tiny accidental movements the user didn’t mean to make.