I’m building a Figma plugin and need help with detecting when a frame gets moved around. I want to execute a function called UpdateLayout()
but only after the user finishes dragging and drops the frame in its new spot.
Right now my code runs whenever I select a frame, but that’s not what I want. I need it to wait until the frame is actually moved to a different location.
figma.on('selectionchange', () => {
const currentSelection = figma.currentPage.selection;
currentSelection.forEach(element => {
if (element.type === 'FRAME') {
console.log(`Frame position is: (${element.x}, ${element.y})`);
UpdateLayout();
}
});
});
The problem is this code triggers when I just click on a frame, not when I actually move it. What’s the right way to detect when a frame has been dragged to a new position?
actually there’s another way thats simpler - you can use currentpage.selection with a position check instead of documentchange events. just compare old vs new coordinates when selection changes and only fire updateLayout if they’re different. way less overhead than documentchange which can get really chatty during complex operations.
You’re listening to the wrong event there. The selectionchange
event fires whenever something gets selected or deselected, which explains why clicking triggers your function. What you actually need is the documentchange
event which fires when properties of nodes get modified, including position changes.
Here’s how I handled this in my 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 approach monitors actual property changes on frame nodes and specifically checks if the x or y coordinates changed. It only triggers after the drag operation completes, not during selection. Much cleaner than trying to track selection states.
I ran into this exact issue when working on a layout management plugin last year. The documentchange approach works but can be quite noisy since it fires for every property modification during the drag operation, not just at the end.
What worked better for me was combining documentchange with a debouncing mechanism. I stored the previous positions and used a timer to delay the UpdateLayout call:
let moveTimer;
let framePositions = new Map();
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'))) {
clearTimeout(moveTimer);
moveTimer = setTimeout(() => {
UpdateLayout();
}, 150);
}
}
});
The 150ms delay ensures UpdateLayout only runs once after the user stops dragging, rather than continuously during the drag operation. This prevented performance issues I was having with complex layouts.