figma-plugin-utilities
v0.1.0
Published
Shared Svelte components and utilities for Figma plugins
Maintainers
Readme
figma-plugin-utils
Shared Svelte components and utilities for Figma plugins.
Installation
npm install figma-plugin-utilsUsage
Import Everything
import {
// Components
PluginLayout,
Header,
Footer,
StatusBar,
EmptyState,
ListItem,
LoadingState,
FieldGroup,
// Utilities
sendToPlugin,
createMessageHandler,
rgbToHex,
hexToRgb,
validateUrl,
validateJsonString,
sanitizeName,
} from "figma-plugin-utils";Import Specific Modules
// Components only
import { PluginLayout, Header, Footer } from "figma-plugin-utils/components";
// Utilities only
import { sendToPlugin, createMessageHandler } from "figma-plugin-utils/lib";Components
| Component | Description |
|-----------|-------------|
| PluginLayout | Main content wrapper with scrollable area |
| Header | Header bar with left, center, right slots and optional title |
| Footer | Footer with right, split, and full layout variants |
| StatusBar | Toast notifications with auto-dismiss (info/success/error/warning) |
| EmptyState | Empty/error states with optional icon and action buttons |
| ListItem | Selectable list items with metadata slot and action menu |
| LoadingState | Centered loading indicator with custom message |
| FieldGroup | Label + input wrapper for form fields |
Header
<Header title="My Plugin">
<svelte:fragment slot="left">
<IconButton iconName={IconBack} on:click={goBack} />
</svelte:fragment>
<svelte:fragment slot="right">
<IconButton iconName={IconSettings} />
</svelte:fragment>
</Header>
<!-- Without border -->
<Header title="Settings" noBorder />Footer
<!-- Right-aligned (default) -->
<Footer>
<Button variant="primary">Save</Button>
</Footer>
<!-- Split layout -->
<Footer variant="split">
<svelte:fragment slot="left">
<Button variant="secondary">Cancel</Button>
</svelte:fragment>
<svelte:fragment slot="right">
<Button variant="primary">Save</Button>
</svelte:fragment>
</Footer>
<!-- Full-width buttons -->
<Footer variant="full">
<Button variant="primary">Generate</Button>
</Footer>StatusBar
<StatusBar
message={status.message}
type={status.type}
on:close={() => status = { message: '', type: 'info' }}
/>Types: info, success, error, warning. Auto-dismisses after 4s for info and success.
EmptyState
<EmptyState
message="No items yet"
icon="search"
actions={[
{ label: "Add Item", handler: handleAdd },
{ label: "Import", handler: handleImport }
]}
/>ListItem
<ListItem
id="item-1"
title="My Item"
active={selectedId === 'item-1'}
menuItems={[
{ label: 'Edit', value: 'edit' },
{ label: 'Delete', value: 'delete' }
]}
on:click={handleSelect}
on:menuSelect={handleMenuAction}
>
<span>Additional metadata</span>
</ListItem>Utilities
Messages (lib/messages.js)
// Send message to plugin code
sendToPlugin("my-action", { data: "value" });
// Handle messages from plugin
window.onmessage = createMessageHandler({
success: (msg) => console.log("Success:", msg),
error: (msg) => console.error("Error:", msg),
});Colors (lib/colors.js)
// Convert between formats (Figma uses 0-1 range)
const rgb = hexToRgb("#FF0000"); // { r: 1, g: 0, b: 0 }
const hex = rgbToHex({ r: 1, g: 0, b: 0 }); // "#FF0000"
// Calculate contrast
const ratio = getContrastRatio(color1, color2);
const passes = meetsContrastLevel(ratio, "AA"); // true/falseValidation (lib/validation.js)
const urlResult = validateUrl("https://example.com");
// { valid: true } or { valid: false, error: "..." }
const jsonResult = validateJsonString('{"key": "value"}');
// { valid: true, parsed: {...} } or { valid: false, error: "..." }
const clean = sanitizeName("My Plugin!!!"); // "My Plugin"Error Handling (lib/errorHandling.js)
// Safe async operations
const result = await safeAsync(
() => fetch(url),
"Loading data"
);
if (result.ok) {
console.log(result.value);
} else {
console.error(result.error.userMessage);
}
// Parse JSON safely
const parsed = parseJsonSafe(jsonString);
// { ok: true, value: {...} } or { ok: false, error: "..." }Figma Helpers (lib/figma-helpers.ts)
For use in code.ts:
import { sendToUI, showError, focusNodes, loadFont } from "figma-plugin-utils/lib/figma-helpers";
// Send message to UI
sendToUI("success", { message: "Done!" });
// Show notification
showError("Something went wrong");
// Focus viewport on nodes
focusNodes(figma.currentPage.selection);
// Load font before using
await loadFont("Inter", "Regular");
// Client storage
await saveToStorage("settings", { theme: "dark" });
const settings = await loadFromStorage("settings", { theme: "light" });