Skip to main content

Injected Libraries and Helpers

This document describes the libraries, CSS frameworks, and helper functions that are automatically available in the FDO iframe UI runtime. These are injected by the FDO application host for plugin UI code. They should not be assumed to exist in the plugin backend/runtime, bootstrap paths, or backend-side render-error fallbacks unless the current host/runtime explicitly proves that. For the full backend-vs-iframe runtime contract, see RENDER_RUNTIME_CONTRACT.md.

Important Boundary: Third-Party Imports

In iframe UI runtime (render() / renderOnLoad() execution):
  • arbitrary npm package import / require is not a supported contract
  • only host-injected globals and helpers are guaranteed
If you need a new UI library in iframe code, it must be added by FDO host injection and documented here first. Backend/plugin runtime code can still import npm dependencies that are bundled with the plugin artifact.

Teaching Boundary: Injected Libraries vs DOM Helpers

SDK DOM helpers are still a best practice for general SDK-native structured UI because they give authors a typed, reusable way to build consistent markup and styling. But this injected-libraries guide serves a different purpose:
  • teach iframe-only host-injected globals
  • teach browser-only runtime behavior
  • teach the UI_MESSAGE backend bridge pattern
So examples in this guide may intentionally use plain markup plus renderOnLoad() wiring instead of DOM helpers, in order to keep the lesson focused. Use this rule:
  • general SDK-native structured UI: DOM helpers are preferred
  • injected-library/runtime-boundary teaching: plain markup is acceptable when it keeps the example focused
If you do use styled DOM helpers in render(), renderHTML(...) remains mandatory so the extracted goober CSS is emitted with the markup.

Important Boundary: JSX-Compatible Markup

Even when you use plain markup in injected-library examples, remember that render() output is consumed by the FDO host transform, not inserted as unconstrained raw HTML. That means the safest mental model is:
  • plain markup is acceptable here for teaching focus
  • but it still needs to be JSX-compatible for the host render pipeline
Examples of what to prefer:
  • <br /> instead of <br>
  • inline element styles or DOM-helper styling instead of raw <style> blocks in render()
  • escaped code samples inside <code> blocks, for example &#123; and &#125;
Examples of what to avoid:
  • raw <style> tags in render()
  • raw object/function braces inside code samples shown directly in JSX-visible markup
Clipboard note:
  • if UI code wants to copy data outside the iframe sandbox, prefer a host-mediated clipboard path
  • if UI code wants to read clipboard data, also prefer a host-mediated clipboard path
  • in the SDK, use the clipboard privileged-action contract instead of assuming direct Electron clipboard access from plugin UI code

Table of Contents

CSS Libraries

The following CSS libraries are automatically loaded in the iframe UI runtime:

Pure CSS (purecss.io)

A set of small, responsive CSS modules that you can use in every web project. Available Classes:
  • .pure-g - Grid container
  • .pure-u-* - Grid units (e.g., .pure-u-1-2 for 50% width)
  • .pure-button - Button styles
  • .pure-form - Form layouts
  • .pure-table - Table styles
  • .pure-menu - Menu/navigation styles
Example:
<div class="pure-g">
    <div class="pure-u-1-2">Half width column</div>
    <div class="pure-u-1-2">Half width column</div>
</div>

Highlight.js

Syntax highlighting for code blocks with the “VS” theme. Usage:
<pre><code class="language-javascript">
const hello = "world";
</code></pre>
<script>hljs.highlightAll();</script>
Available via:
  • CSS: Pre-loaded VS theme
  • JS: window.hljs object

Notyf

Modern notification library for displaying toast messages. Available via:
  • CSS: Pre-loaded styles
  • JS: window.Notyf class
Example:
const notyf = new Notyf({
    duration: 3000,
    position: { x: 'right', y: 'top' }
});
notyf.success('Operation successful!');
notyf.error('Something went wrong!');

JavaScript Libraries

FontAwesome

Complete icon library with all icon sets (solid, regular, brands). Available Sets:
  • FontAwesome Solid
  • FontAwesome Regular
  • FontAwesome Brands
Usage:
<i class="fas fa-home"></i>
<i class="far fa-star"></i>
<i class="fab fa-github"></i>

Split Grid

Advanced grid splitter for creating resizable layouts. Available via: window.Split function Example:
Split({
    columnGutters: [{
        track: 1,
        element: document.querySelector('.gutter-col-1'),
    }],
    rowGutters: [{
        track: 1,
        element: document.querySelector('.gutter-row-1'),
    }]
});

Goober

Lightweight CSS-in-JS library (already exposed via SDK’s DOM classes). Available via: window.goober Note: While goober is loaded, the SDK’s DOM classes provide a more convenient interface for styling. Refer to the SDK documentation for usage.

ACE Editor

Powerful code editor component. Available via: window.ace Example:
const editor = ace.edit("editor");
editor.setTheme("ace/theme/monokai");
editor.session.setMode("ace/mode/javascript");

Window Helper Functions

These helper functions are injected into the iframe UI runtime window object.

createBackendReq(type, data)

Creates a request to your plugin’s backend transport. Parameters:
  • type (string): The backend transport type
  • data (any, optional): The data to send to the backend
Returns: Promise<any> - The response from the backend Example:
const result = await window.createBackendReq("UI_MESSAGE", {
    handler: "plugin.getUserData",
    content: { userId: 123 }
});
console.log(result);
For production plugins, register handlers in init() and call them through UI_MESSAGE. Do not assume arbitrary handler names are transport types. If a UI_MESSAGE handler returns a privileged-action envelope for requestPrivilegedAction, extract the validated request object before sending it to the host bridge:
const envelopeOrRequest = await window.createBackendReq("UI_MESSAGE", {
    handler: "plugin.buildPrivilegedRequest",
    content: { /* handler payload */ }
});

const requestPayload =
    envelopeOrRequest?.result?.request ??
    envelopeOrRequest?.request ??
    envelopeOrRequest;

const response = await window.createBackendReq("requestPrivilegedAction", requestPayload);
Do not pass the entire backend envelope object directly into requestPrivilegedAction.

waitForElement(selector, callback, timeout)

Waits for an element to appear in the DOM. Parameters:
  • selector (string): CSS selector for the element
  • callback (function): Callback function called when element is found
  • timeout (number, optional): Timeout in milliseconds (default: 5000)
Example:
window.waitForElement('#my-dynamic-element', (element) => {
    console.log('Element found:', element);
    element.style.color = 'red';
}, 10000);

executeInjectedScript(scriptContent)

Executes a script in the plugin context. Parameters:
  • scriptContent (string): The JavaScript code to execute
Example:
window.executeInjectedScript(`
    console.log('This code runs in the plugin context');
    // Your dynamic script here
`);

addGlobalEventListener(eventType, callback)

Adds a global event listener to the window. Parameters:
  • eventType (string): The event type (e.g., ‘click’, ‘keydown’)
  • callback (function): The event handler function
Example:
window.addGlobalEventListener('resize', (event) => {
    console.log('Window resized:', window.innerWidth, window.innerHeight);
});

removeGlobalEventListener(eventType, callback)

Removes a global event listener from the window. Parameters:
  • eventType (string): The event type
  • callback (function): The event handler function to remove
Example:
const handleResize = (event) => {
    console.log('Resize event');
};

window.addGlobalEventListener('resize', handleResize);
// Later...
window.removeGlobalEventListener('resize', handleResize);

applyClassToSelector(className, selector)

Applies a CSS class to an element matching the selector. Parameters:
  • className (string): The CSS class name to add
  • selector (string): CSS selector for the target element
Example:
window.applyClassToSelector('highlight', '#my-element');

Usage Examples

Example 1: Creating a Notification System

export default class NotificationPlugin extends FDO_SDK {
    render() {
        return `
            <div>
                <button onclick="showSuccess()">Show Success</button>
                <button onclick="showError()">Show Error</button>
            </div>
            <script>
                const notyf = new Notyf({
                    duration: 3000,
                    position: { x: 'right', y: 'top' }
                });
                
                function showSuccess() {
                    notyf.success('Operation completed successfully!');
                }
                
                function showError() {
                    notyf.error('An error occurred!');
                }
            </script>
        `;
    }
}

Example 2: Code Editor with Syntax Highlighting

export default class CodeEditorPlugin extends FDO_SDK {
    render() {
        return `
            <div id="editor" style="height: 400px;"></div>
            <script>
                window.waitForElement('#editor', (element) => {
                    const editor = ace.edit("editor");
                    editor.setTheme("ace/theme/monokai");
                    editor.session.setMode("ace/mode/javascript");
                    editor.setValue("// Start coding...");
                });
            </script>
        `;
    }
}

Example 3: Responsive Grid Layout

export default class GridLayoutPlugin extends FDO_SDK {
    render() {
        return `
            <div class="pure-g">
                <div class="pure-u-1 pure-u-md-1-2 pure-u-lg-1-3">
                    <div class="pure-button">Column 1</div>
                </div>
                <div class="pure-u-1 pure-u-md-1-2 pure-u-lg-1-3">
                    <div class="pure-button">Column 2</div>
                </div>
                <div class="pure-u-1 pure-u-md-1-2 pure-u-lg-1-3">
                    <div class="pure-button">Column 3</div>
                </div>
            </div>
        `;
    }
}

Example 4: Backend Communication

export default class DataPlugin extends FDO_SDK {
    init() {
        PluginRegistry.registerHandler("data.getActive", async (content) => {
            return { filter: content?.filter ?? "active", items: [] };
        });
    }
    
    render() {
        return `
            <div id="data-container">Loading...</div>
            <script>
                window.waitForElement('#data-container', async (element) => {
                    try {
                        const data = await window.createBackendReq("UI_MESSAGE", {
                            handler: "data.getActive",
                            content: { filter: "active" }
                        });
                        element.innerHTML = JSON.stringify(data, null, 2);
                    } catch (error) {
                        element.innerHTML = 'Error loading data';
                    }
                });
            </script>
        `;
    }
}

Example 5: Split Panel Layout

export default class SplitPanelPlugin extends FDO_SDK {
    render() {
        return `
            <style>
                .grid {
                    display: grid;
                    grid-template-columns: 1fr 10px 1fr;
                    height: 400px;
                }
                .gutter {
                    background-color: #ccc;
                    cursor: col-resize;
                }
                .panel {
                    padding: 20px;
                    overflow: auto;
                }
            </style>
            <div class="grid">
                <div class="panel">Left Panel</div>
                <div class="gutter gutter-col-1"></div>
                <div class="panel">Right Panel</div>
            </div>
            <script>
                Split({
                    columnGutters: [{
                        track: 1,
                        element: document.querySelector('.gutter-col-1'),
                    }]
                });
            </script>
        `;
    }
}

Best Practices

  1. Use TypeScript types: The SDK provides TypeScript definitions for all window helper functions
  2. Error handling: Always wrap backend requests in try-catch blocks
  3. Element waiting: Use waitForElement instead of setTimeout for DOM-dependent code
  4. Cleanup: Remove event listeners when they’re no longer needed
  5. CSP Compliance: Be aware of Content Security Policy restrictions in the plugin environment

Additional Resources