Plugins
Plugin UI Guide
Build polished plugin interfaces using HTML, CSS, and Figma's design patterns.
Plugin UIs run in an iframe and can use any web technology. This guide covers best practices for building interfaces that feel native to Figma.
UI Basics
The UI is an HTML file loaded in an iframe. It communicates with the plugin sandbox via postMessage:
<div id="app">
<label>Layer name</label>
<input type="text" id="name-input" placeholder="Enter name...">
<button id="apply-btn">Apply</button>
</div>
<script>
document.getElementById('apply-btn').onclick = () => {
const name = document.getElementById('name-input').value;
parent.postMessage(
{ pluginMessage: { type: 'rename', name } },
'*'
);
};
// Receive messages from the plugin
onmessage = (event) => {
const msg = event.data.pluginMessage;
if (msg.type === 'selection-changed') {
document.getElementById('name-input').value = msg.name;
}
};
</script>
Sizing the UI
Set the UI dimensions when showing it:
- Modal
- Resizable
Styling Best Practices
Use styles that match Figma’s native interface:
/* Base styles matching Figma's UI */
:root {
--figma-color-bg: #ffffff;
--figma-color-text: #333333;
--figma-color-border: #e5e5e5;
--figma-color-primary: #0d99ff;
--figma-radius: 6px;
--figma-font: Inter, -apple-system, sans-serif;
}
body {
margin: 0;
padding: 12px;
font-family: var(--figma-font);
font-size: 11px;
color: var(--figma-color-text);
background: var(--figma-color-bg);
}
input, select {
width: 100%;
padding: 6px 8px;
border: 1px solid var(--figma-color-border);
border-radius: var(--figma-radius);
font-size: 11px;
font-family: inherit;
outline: none;
}
input:focus {
border-color: var(--figma-color-primary);
box-shadow: 0 0 0 1px var(--figma-color-primary);
}
button {
padding: 6px 16px;
border: none;
border-radius: var(--figma-radius);
background: var(--figma-color-primary);
color: white;
font-size: 11px;
font-weight: 500;
cursor: pointer;
}
Figma provides CSS variables for theming. When running inside Figma, you can use figma-color-bg, figma-color-text, and other tokens to match the current Figma theme (light or dark).
Handling Network Requests
Since the main thread can’t access fetch, route network calls through the UI:
// code.ts — request data from UI
figma.ui.postMessage({ type: 'fetch-data', url: 'https://api.example.com/data' });
figma.ui.onmessage = (msg) => {
if (msg.type === 'fetch-response') {
// Use the fetched data
console.log(msg.data);
}
};
<!-- ui.html — handle fetch requests -->
<script>
onmessage = async (event) => {
const msg = event.data.pluginMessage;
if (msg.type === 'fetch-data') {
const response = await fetch(msg.url);
const data = await response.json();
parent.postMessage(
{ pluginMessage: { type: 'fetch-response', data } },
'*'
);
}
};
</script>