React Figma plugin message communication between UI and code files failing

I’m building a Figma plugin using React and running into trouble with message passing between the UI component and the main code file.

I have a button in my UI that triggers this function:

// ui.tsx
handleClick = () => {
    parent.postMessage({pluginMessage: {type: 'FetchSelection'}}, '*');
};

This message gets sent to my main plugin file successfully:

// code.ts
figma.ui.onmessage = message => {
  if (message.type === 'FetchSelection') {
    figma.ui.postMessage({"elementName": figma.currentPage.selection[0].name});
  }
};

The problem is that when code.ts tries to send data back to the UI, nothing happens. I have this listener in my UI file:

// ui.tsx
onmessage = (data) => {
    console.log(data);
};

But this function never gets called. The message from code.ts to ui.tsx just disappears. I need to get the selected element data from the main thread to my React component but can’t figure out why the return message isn’t working. Has anyone dealt with this before?

Had this exact issue when I was working on my first Figma plugin last year. The problem is with how you’re setting up the message listener in your React component. The onmessage property you’re using is for the global window object, but in a Figma plugin UI context, you need to listen specifically for messages from the plugin’s main thread. Replace your current listener with: window.onmessage = (event) => { console.log(event.data); }; The key difference is using window.onmessage and accessing event.data instead of just data. Also make sure this listener is set up when your component mounts, not just declared as a function. Once I made this change, the communication worked perfectly in both directions.

I ran into something similar when building my plugin about three months ago. Your message listener syntax is definitely the issue here. The way you have it set up with just onmessage = (data) => {} won’t work in the Figma plugin environment because of how the iframe communication works. What fixed it for me was using window.onmessage = (event) => { console.log(event.data); } and making sure to access the data through event.data rather than the direct parameter. The timing also matters - if you’re using React hooks, wrap the listener setup in useEffect to ensure it runs after the component mounts. One thing that caught me off guard was that the listener can sometimes get overwritten if you’re not careful about where you place it in your component lifecycle. Double check that your code.ts is actually executing by adding a console.log or figma.notify before the postMessage call to rule out any selection issues.

I encountered similar communication issues when developing my plugin six months ago. The root cause in your case appears to be the message listener setup. You’re using onmessage = (data) => {} but this won’t capture messages from the Figma plugin sandbox properly. Instead, you need to use window.addEventListener('message', (event) => { console.log(event.data); }) in your React component. The addEventListener approach is more reliable for cross-context communication in Figma plugins. Also, make sure you’re calling this inside a useEffect hook if you’re using functional components, or in componentDidMount for class components. The timing of when you set up the listener matters significantly. Another thing to check is whether your main thread code is actually executing - add a console.log right before the postMessage call in code.ts to verify it’s reaching that point.

check if you’re using the right event structure - i had same problem and turns out the listener needs to be window.onmessage = (e) => console.log(e.data) not just onmessage. also make sure your code.ts is actually running that postmessage line, maybe add a figma.notify() there to test it fires