Figma-Plugin erstellen: Einstieg in die Plugin-API
Wie Hauptcode und Oberfläche eines Figma-Plugins zusammenarbeiten, wie Sie Ebenen lesen und erzeugen und was bis zur Veröffentlichung in der Figma Community zu beachten ist.
Ein Figma-Plugin erstellen Sie aus drei Bausteinen: einer manifest.json, einem Hauptcode, der in einer Sandbox direkt mit dem Figma-Dokument arbeitet, und einer optionalen HTML-Oberfläche in einem eingebetteten Fenster. Beide Teile kommunizieren über Nachrichten. Den Einstieg bietet die Desktop-App von Figma, die ein Grundgerüst erzeugt und lokale Plugins zum Testen lädt.
Die Architektur: zwei getrennte Welten
Dieser Aufbau ist der wichtigste Unterschied zu anderen Plattformen und die häufigste Quelle für Verwirrung beim Einstieg.
Hauptcode (main) |
Oberfläche (ui) |
|
|---|---|---|
| Läuft in | Sandbox im Figma-Prozess | eingebettetem Browserfenster (iframe) |
| Zugriff auf das Dokument | ja, über das Objekt figma |
nein |
| Browser-DOM und Web-APIs | nein, nur ein eingeschränkter JavaScript-Umfang | ja |
| Sendet Nachrichten mit | figma.ui.postMessage() |
parent.postMessage({ pluginMessage }, "*") |
| Empfängt Nachrichten mit | figma.ui.onmessage |
window.onmessage |
Ein Plugin ohne Oberfläche kommt mit dem Hauptcode allein aus, etwa ein Befehl, der alle ausgewählten Ebenen umbenennt. Sobald Eingaben, Vorschauen oder Listen nötig sind, kommt das UI-Fenster dazu.
Ein Plugin anlegen
- Öffnen Sie eine Design-Datei in der Desktop-App von Figma.
- Wählen Sie im Menü unter Plugins den Bereich Development und dort die Option, ein neues Plugin anzulegen.
- Vergeben Sie einen Namen, wählen Sie den Editor (Figma Design, FigJam oder beide) und eine Vorlage, etwa mit leerer Oberfläche.
- Speichern Sie den erzeugten Ordner, installieren Sie die Abhängigkeiten mit
npm installund starten Sie den TypeScript-Compiler im Beobachtungsmodus. - Starten Sie das Plugin über Plugins, Development und den Namen Ihres Plugins.
Ein bereits vorhandenes Projekt importieren Sie im selben Menü über die Option zum Import aus einer Manifest-Datei.
Das Manifest
{
"name": "Ebenen-Umbenenner",
"id": "wird-von-figma-vergeben",
"api": "1.0.0",
"main": "code.js",
"ui": "ui.html",
"editorType": ["figma"],
"documentAccess": "dynamic-page",
"networkAccess": { "allowedDomains": ["none"] }
}
Die wichtigsten Felder:
idvergibt Figma beim Anlegen oder spätestens beim Veröffentlichen. Sie verbindet Ihren Code mit dem Eintrag in der Community.mainunduizeigen auf die gebaute JavaScript-Datei und die HTML-Datei der Oberfläche.editorTypelegt fest, in welchen Editoren das Plugin erscheint, etwa in Figma Design, FigJam oder dem Dev Mode.documentAccess: "dynamic-page"bedeutet, dass Seiten einer Datei erst bei Bedarf geladen werden. Ihr Code muss deshalb für Zugriffe auf andere Seiten die asynchronen Varianten der API nutzen.networkAccesslistet die Domains, die das Plugin ansprechen darf. Wer keine Netzwerkverbindung braucht, gibt"none"an. Diese Angabe ist für Nutzer in der Community sichtbar.
Der Hauptcode
Das globale Objekt figma ist der Zugang zum Dokument. Ein kleines Beispiel ohne Oberfläche, das ausgewählte Ebenen nummeriert:
const auswahl = figma.currentPage.selection;
if (auswahl.length === 0) {
figma.notify("Bitte zuerst Ebenen auswählen.");
} else {
auswahl.forEach((knoten, i) => {
knoten.name = `Element ${i + 1}`;
});
figma.notify(`${auswahl.length} Ebenen umbenannt.`);
}
figma.closePlugin();
Zwei Regeln gelten für fast jedes Plugin:
figma.closePlugin()aufrufen. Ein Plugin läuft so lange, bis es sich selbst beendet oder die Person es schließt. Ohne diesen Aufruf bleibt ein Plugin ohne Oberfläche sichtbar aktiv.- Knotentypen prüfen. Nicht jeder Knoten hat jede Eigenschaft. Ein Text hat Zeichen, ein Rahmen hat Kinder. Mit
knoten.type === "TEXT"oder dem Operator"children" in knotenvermeiden Sie Laufzeitfehler, und TypeScript hilft dabei mit den passenden Typen.
Ebenen erzeugen und Texte ändern
Neue Elemente erzeugen Sie mit Fabrikmethoden wie figma.createRectangle(), figma.createFrame() oder figma.createText(). Bei Texten gibt es eine Besonderheit: Bevor Sie Zeichen oder Schrift ändern, muss die verwendete Schrift mit await figma.loadFontAsync(...) geladen sein. Wer das vergisst, bekommt einen Fehler, sobald das Plugin characters setzt.
const text = figma.createText();
await figma.loadFontAsync({ family: "Inter", style: "Regular" });
text.characters = "Hallo aus dem Plugin";
figma.currentPage.appendChild(text);
figma.viewport.scrollAndZoomIntoView([text]);
Die Oberfläche und der Nachrichtenaustausch
Die Oberfläche öffnen Sie im Hauptcode mit figma.showUI(__html__, { width: 320, height: 240 }). Die Variable __html__ enthält den Inhalt der im Manifest genannten HTML-Datei. Danach läuft alles über Nachrichten:
// code.ts (Hauptcode)
figma.showUI(__html__, { width: 300, height: 160 });
figma.ui.onmessage = (nachricht: { typ: string; anzahl?: number }) => {
if (nachricht.typ === "rechtecke") {
for (let i = 0; i < (nachricht.anzahl ?? 1); i++) {
const r = figma.createRectangle();
r.x = i * 120;
}
}
figma.closePlugin();
};
<!-- ui.html -->
<input id="anzahl" type="number" value="3">
<button id="los">Rechtecke erzeugen</button>
<script>
document.getElementById("los").onclick = () => {
const anzahl = Number(document.getElementById("anzahl").value);
parent.postMessage({ pluginMessage: { typ: "rechtecke", anzahl } }, "*");
};
</script>
Nachrichten werden als Kopie übertragen. Knoten selbst lassen sich nicht senden, übergeben Sie stattdessen IDs oder einfache Daten. Für größere Oberflächen setzen viele Entwickler ein Framework ein und bündeln HTML, CSS und JavaScript zu einer einzigen Datei, denn Figma lädt nur die im Manifest genannte HTML-Datei. Wie ein solches Build-Setup aussieht, zeigt der Beitrag TypeScript und Vite für Erweiterungen einrichten.
Auf Änderungen reagieren
Plugins mit Oberfläche bleiben oft geöffnet, während Menschen weiterarbeiten. Damit die Anzeige aktuell bleibt, registrieren Sie Ereignis-Listener im Hauptcode. Das häufigste Ereignis ist die Änderung der Auswahl:
figma.on("selectionchange", () => {
const namen = figma.currentPage.selection.map((k) => k.name);
figma.ui.postMessage({ typ: "auswahl", namen });
});
Weitere Ereignisse melden etwa einen Seitenwechsel (currentpagechange) oder das Schließen des Plugins (close). Bei Dokumentänderungen ist Vorsicht geboten: Ein Listener, der bei jeder kleinen Änderung große Teile der Datei durchsucht, bremst die Arbeit spürbar. Fassen Sie Aktualisierungen deshalb zusammen und verarbeiten Sie nur die Knoten, die sich tatsächlich geändert haben.
Große Dateien und Performance
Design-Dateien können Zehntausende Knoten enthalten. Ein Plugin, das rekursiv jede Ebene besucht, friert die Oberfläche dann für Sekunden ein, denn der Hauptcode läuft im selben Ablauf wie die Bearbeitung. Einige Gewohnheiten helfen:
- Gezielt suchen. Statt alle Kinder selbst zu durchlaufen, nutzen Sie
findAllWithCriteria()mit Typfiltern. Diese Methode ist für typische Suchen deutlich schneller als eine eigene Schleife. - Mit der Auswahl arbeiten. Wo es fachlich passt, beschränkt sich das Plugin auf ausgewählte Ebenen statt auf die ganze Datei.
- Fortschritt zeigen. Bei langen Operationen teilen Sie die Arbeit in Abschnitte auf und melden über die Oberfläche oder
figma.notify(), wie weit das Plugin ist. - Nur einmal schreiben. Jede Änderung an einem Knoten löst intern Arbeit aus. Berechnen Sie zuerst alle neuen Werte und setzen Sie sie dann in einem Durchgang.
Änderungen eines Plugin-Laufs lassen sich übrigens mit einem einzigen Rückgängig-Schritt zurücknehmen. Das ist bequem für Nutzer, bedeutet aber auch, dass ein fehlerhaftes Plugin viele Änderungen auf einmal anrichten kann. Testen Sie deshalb in Kopien echter Dateien.
TypeScript und Typdefinitionen
Die Vorlagen von Figma nutzen TypeScript mit dem Paket @figma/plugin-typings. Damit kennt Ihr Editor alle Knotentypen, Eigenschaften und Methoden. Gerade bei der API von Figma mit ihren vielen Knotentypen sparen die Typen viel Zeit, weil Tippfehler und fehlende Typprüfungen schon beim Schreiben auffallen.
Daten speichern
Für Einstellungen einer Person bietet figma.clientStorage einen asynchronen Speicher, der lokal auf dem Gerät liegt. Daten, die zu einem Element gehören und mit der Datei geteilt werden sollen, speichern Sie mit setPluginData() direkt am Knoten. Diese Daten kann nur Ihr Plugin lesen. Für Daten, die auch andere Plugins sehen dürfen, gibt es setSharedPluginData() mit einem eigenen Namensraum.
Typische Fehler beim Einstieg
| Symptom | Ursache | Lösung |
|---|---|---|
document is not defined im Hauptcode |
DOM gibt es nur im UI-Teil | Logik aufteilen, Nachrichten nutzen |
| Fehler beim Setzen von Text | Schrift nicht geladen | figma.loadFontAsync() vorher aufrufen |
| Zugriff auf andere Seite schlägt fehl | dynamisches Laden von Seiten | asynchrone Methoden wie getNodeByIdAsync() |
| Netzwerkanfrage blockiert | Domain fehlt in allowedDomains |
Domain im Manifest eintragen |
| Plugin bleibt aktiv | closePlugin() fehlt |
nach getaner Arbeit beenden |
Veröffentlichen in der Figma Community
Öffentlich verfügbar wird ein Plugin über die Figma Community. Die Einreichung starten Sie in der Desktop-App über die Verwaltung Ihrer Plugins. Sie brauchen einen Namen, eine Beschreibung, ein Symbol, ein Titelbild und Angaben zu Datenzugriff und Netzwerkverbindungen. Figma prüft neue Plugins vor der Freigabe, spätere Versionen veröffentlichen Sie direkt aus der App.
Figma ermöglicht für bestimmte Konten auch kostenpflichtige Plugins. Welche Voraussetzungen gelten, regeln die aktuellen Bedingungen der Figma Community. Begriffe wie Sandbox, Manifest und Nachrichtenaustausch erklärt das Glossar. Wer neben Figma auch Notiz-Apps erweitern möchte, findet im Artikel Obsidian-Plugin entwickeln ein Gegenmodell ohne Sandbox.
Fragen und Antworten
- Kann ich ein Figma-Plugin im Browser entwickeln?
- Ausführen lassen sich Plugins auch in der Browser-Version, für die Entwicklung brauchen Sie aber die Desktop-App. Nur dort können Sie ein Plugin aus einer lokalen manifest.json importieren und während der Arbeit immer wieder neu starten.
- Warum kann mein Hauptcode nicht auf document oder fetch wie gewohnt zugreifen?
- Der Hauptcode läuft in einer Sandbox ohne Browser-DOM. Er sieht das Figma-Dokument über das globale Objekt figma, aber keine Webseite. Alles, was ein echtes Browserfenster braucht, etwa komplexe Oberflächen oder bestimmte Web-APIs, gehört in den UI-Teil, der seine Ergebnisse per Nachricht zurückschickt.
- Was ist der Unterschied zwischen einem Plugin und einem Widget?
- Ein Plugin wird von einer Person gestartet, erledigt eine Aufgabe und beendet sich wieder. Ein Widget ist ein dauerhaftes, interaktives Objekt auf der Arbeitsfläche, das alle Beteiligten einer Datei sehen und bedienen können. Beide nutzen ähnliche APIs, sind aber getrennte Produkttypen.
- Muss ich mein Plugin veröffentlichen, um es im Team zu nutzen?
- Nein. Je nach Tarif können Organisationen Plugins privat für ihre Mitglieder bereitstellen. Für einzelne Personen genügt während der Entwicklung der Import über die Desktop-App. Öffentlich in der Figma Community erscheint ein Plugin nur nach einer Einreichung.
Weiterlesen
- Obsidian-Plugin entwickeln
Von der offiziellen Vorlage über Befehle, Einstellungen und Ereignisse bis zur Einreichung im Verzeichnis der Community-Plugins: so entsteht ein Obsidian-Plugin.
- TypeScript und Vite einrichten
Ein Build-Setup für Erweiterungen: TypeScript-Konfiguration, Typen für die Browser-APIs, mehrere Einstiegspunkte mit Vite, die Sonderrolle der Content Scripts und Alternativen wie WXT.
- Glossar
Von Add-on bis WebExtensions: die wichtigsten Fachbegriffe der Plugin-Entwicklung in kurzen, plattformübergreifenden Erklärungen.