Skip to main content
The SDK provides a family of typed DOM helper classes for building plugin UI. Each class targets a specific category of HTML element. You instantiate them in render() and compose their outputs into the string your plugin returns to the FDO host. All DOM classes extend the base DOM class, which gives every helper a common set of capabilities: CSS-in-JS styling via goober, extra CSS classes, inline style objects, custom HTML attributes, event handlers, and accessibility attributes.
DOM helpers run in the plugin backend runtime (inside render()). They produce HTML strings consumed by the FDO iframe host pipeline. Do not call DOM helpers from inside <script> blocks or renderOnLoad() — those run in the iframe.

Common options

Every DOM helper method accepts an options parameter typed as Partial<typeof DOM.DEFAULT_OPTIONS>:
{
  classes?: string[];           // extra CSS class names to append
  style?: Record<string, string>; // inline styles as a JS object
  disableDefaultClass?: boolean;  // strip the helper's built-in default class
}
Most methods also accept:
  • id?: string — sets the element’s id attribute. If omitted, the SDK generates a random one.
  • otherProps?: Record<string, any> — additional HTML attributes (scope, colspan, width, loading, etc.).
  • customAttributes?: Record<string, string> — on methods that take extended options, merges arbitrary HTML attributes directly onto the element.

CSS-in-JS with goober

The base DOM class wraps goober for CSS-in-JS. Goober is injected into the iframe runtime as window.goober, but you interact with it through the helper methods on any DOM instance:
const dom = new DOMText();

// Generate a scoped class name from a style object
const cardClass = dom.createClassFromStyle({
  "background-color": "#f0f4ff",
  "border-radius": "8px",
  padding: "16px",
});

// Generate a keyframe animation class name
const spinClass = dom.createStyleKeyframe(`
  from { transform: rotate(0deg); }
  to   { transform: rotate(360deg); }
`);
Both methods return a generated class name you can pass into the classes option of any element. The generated <style> block is extracted and prepended automatically when you call renderHTML().
render(): string {
  const dom = new DOMNested();
  const cardClass = dom.createClassFromStyle({ padding: "20px", background: "#fff" });
  const card = dom.createBlockDiv(["Hello"], { classes: [cardClass] });
  return dom.renderHTML(card);
}
You rarely need to call renderHTML() explicitly — FDO’s host pipeline injects goober styles for you. Use renderHTML() only if you need the styles embedded directly in the returned string.

DOMText

DOMText creates text-level and block-level text elements.
import { DOMText } from "@anikitenko/fdo-sdk";
const text = new DOMText();
MethodElementNotes
createHText(level, content, options?, id?)h1h6level must be 1–6 or throws
createPText(content, options?, id?)p
createSpanText(content, options?, id?)span
createText(content, options?, id?)spanalias for createSpanText
createDivText(content, options?, id?)div
createStrongText(content, options?, id?)strong
createEmText(content, options?, id?)em
createBText(content, options?, id?)b
createIText(content, options?, id?)i
createCodeText(content, options?, id?)code
createPreText(content, options?, id?)pre
createBlockQuoteText(content, options?, id?)blockquote
createMarkText(content, options?, id?)mark
createSmallText(content, options?, id?)small
createKbdText(content, options?, id?)kbd
createUText(content, options?, id?)u
createSText(content, options?, id?)s
createInsText(content, options?, id?)ins
createCiteText(content, options?, id?)cite
createAbbrText(content, title, options?, id?)abbradds title attribute
createLabelText(content, htmlFor, options?, id?)labeladds htmlFor attribute
Content passed to DOMText methods is HTML-escaped automatically, so user-supplied strings are safe to pass directly.
const text = new DOMText();

const heading  = text.createHText(1, "Dashboard");
const subhead  = text.createHText(2, "Runtime Health", { style: { color: "#667085" } });
const para     = text.createPText("All systems operational.");
const badge    = text.createSpanText("Healthy", {
  style: { color: "#1f8a3d", fontWeight: "600" },
});

DOMButton

DOMButton creates <button> elements with attached event handlers.
import { DOMButton } from "@anikitenko/fdo-sdk";
const button = new DOMButton();
createButton(
  label: string,
  onClick: Function,
  options?: Partial<typeof DOM.DEFAULT_OPTIONS>,
  id?: string,
  otherProps?: Record<string, any>
): string
The default class applied is pure-button (from the injected PureCSS library), giving you zero-config button styling.
const button = new DOMButton();

const primary = button.createButton(
  "Register Session",
  () => {},
  {
    style: {
      marginTop: "12px",
      padding: "8px 12px",
      borderRadius: "4px",
      border: "1px solid #0b65d8",
      color: "#0b65d8",
      backgroundColor: "#eef5ff",
      cursor: "pointer",
    },
  },
  "register-session-button"
);
Event handler functions are serialized to strings for the iframe context. Keep handlers simple — they cannot close over backend-runtime variables.

DOMLink creates <a> anchor elements. Unlike most helpers, you pass options at construction time.
import { DOMLink } from "@anikitenko/fdo-sdk";
constructor(
  id: string,
  styleOptions?: Partial<typeof DOM.DEFAULT_OPTIONS>,
  props?: Record<string, any>
)
createLink(label: string, href: string): string
const link = new DOMLink("docs-link", {
  style: { color: "#0b65d8", textDecoration: "none" },
});

const anchor = link.createLink("Open plugin author docs", "https://plugins.fdo.alexvwan.me");

DOMTable

DOMTable creates full table structures — <table>, <thead>, <tbody>, <tfoot>, <tr>, <th>, <td>, and <caption>.
import { DOMTable } from "@anikitenko/fdo-sdk";
const table = new DOMTable();
Build tables bottom-up: cells → rows → sections → table.
const table = new DOMTable();
const text  = new DOMText();

// Header row
const thead = table.createTableHead([
  table.createTableRow([
    table.createTableHeader([text.createStrongText("Environment")]),
    table.createTableHeader([text.createStrongText("Status")]),
    table.createTableHeader([text.createStrongText("Latency")]),
  ]),
]);

// Data rows
const tbody = table.createTableBody([
  table.createTableRow([
    table.createTableCell(["Production"]),
    table.createTableCell([text.createSpanText("Healthy", { style: { color: "#1f8a3d", fontWeight: "600" } })]),
    table.createTableCell(["42ms"]),
  ]),
  table.createTableRow([
    table.createTableCell(["Staging"]),
    table.createTableCell([text.createSpanText("Degraded", { style: { color: "#b06d00", fontWeight: "600" } })]),
    table.createTableCell(["190ms"]),
  ]),
]);

// Assemble
const dataTable = table.createTable(
  [
    table.createCaption([text.createStrongText("Runtime Health Snapshot")]),
    thead,
    tbody,
  ],
  { style: { width: "100%", borderCollapse: "collapse", marginTop: "12px" } },
  "health-table"
);
Pass otherProps to createTableHeader or createTableCell for attributes like scope, colspan, and rowspan:
table.createTableHeader(["Name"], {}, undefined, { scope: "col" });
table.createTableCell(["Total"], {}, undefined, { colspan: "3" });

DOMInput

DOMInput creates form controls: <input>, <textarea>, <select>, <option>, and <optgroup>. Options and props are passed at construction.
import { DOMInput } from "@anikitenko/fdo-sdk";
constructor(
  id: string,
  styleOptions?: Partial<typeof DOM.DEFAULT_OPTIONS>,
  props?: Record<string, any>
)
const input = new DOMInput("username-input", {
  style: {
    padding: "8px",
    border: "1px solid #ccc",
    borderRadius: "4px",
    width: "280px",
  },
});

const textField = input.createInput("text");
const area      = input.createTextarea();
Build select dropdowns by composing options and optgroups:
const placeholder = new DOMInput("", {}).createOption("Select an option", "", true);
const optA        = new DOMInput("", {}).createOption("Option A", "a");
const optB        = new DOMInput("", {}).createOption("Option B", "b");

const select = new DOMInput("my-select", {}).createSelect(
  [placeholder, optA, optB],
  () => { /* onChange handler */ }
);
Group options with createOptgroup:
const g1opt1 = new DOMInput("", {}).createOption("Item 1", "1");
const g1opt2 = new DOMInput("", {}).createOption("Item 2", "2");
const group1 = new DOMInput("", {}).createOptgroup("Group 1", [g1opt1, g1opt2]);

const grouped = new DOMInput("grouped-select", {}).createSelect([group1]);

DOMMedia

DOMMedia creates self-closing <img> elements with built-in accessibility support.
import { DOMMedia } from "@anikitenko/fdo-sdk";
const media = new DOMMedia();
createImage(
  src: string,
  alt: string,
  options?: Partial<typeof DOM.DEFAULT_OPTIONS & { customAttributes?: Record<string, string> }>,
  id?: string,
  otherProps?: Record<string, any>
): string
Always provide a meaningful alt value. Pass width, height, and loading through otherProps:
const media = new DOMMedia();

const logo = media.createImage(
  "/assets/logo.png",
  "Company Logo",
  { classes: ["logo-image"] },
  undefined,
  { width: "200", height: "100", loading: "lazy" }
);

DOMSemantic

DOMSemantic creates HTML5 semantic container elements: <article>, <section>, <nav>, <header>, <footer>, <aside>, and <main>.
import { DOMSemantic } from "@anikitenko/fdo-sdk";
const semantic = new DOMSemantic();
Each method follows the same signature:
create*(children: any[], options?, id?): string
Use semantic elements to give your plugin’s layout meaningful structure:
const semantic = new DOMSemantic();
const text     = new DOMText();

return semantic.createMain(
  [
    semantic.createHeader([
      text.createHText(1, "Advanced DOM Example"),
      text.createPText("Demonstrates advanced composition with DOM helper classes", {
        style: { color: "#667085" },
      }),
    ]),
    semantic.createSection(
      [text.createHText(2, "Health Table"), dataTable],
      { style: { marginTop: "14px" } }
    ),
    semantic.createSection(
      [text.createHText(2, "Operator Form"), formSection],
      { style: { marginTop: "18px" } }
    ),
    semantic.createFooter(
      [text.createPText("Need more details?"), link.createLink("Open docs", "https://...")],
      { style: { marginTop: "20px", borderTop: "1px solid #e5e7eb" } }
    ),
  ],
  { style: { padding: "20px", fontFamily: "system-ui, sans-serif" } }
);

DOMNested

DOMNested creates container and list elements: <div>, <ul>, <ol>, <li>, <dl>, <dt>, <dd>, <form>, <fieldset>, and <legend>.
import { DOMNested } from "@anikitenko/fdo-sdk";
const nested = new DOMNested();

Block containers and forms

nested.createBlockDiv(children, options?, id?): string
nested.createForm(children, options?, id?): string
nested.createFieldset(children, options?, id?): string
nested.createLegend(children, options?, id?): string

Lists

nested.createList(children, options?, id?): string         // <ul>
nested.createOrderedList(children, options?, id?): string  // <ol>
nested.createListItem(children, options?, id?): string     // <li>
const nested = new DOMNested();

const steps = nested.createOrderedList([
  nested.createListItem(["Install the SDK"]),
  nested.createListItem(["Create your plugin"]),
  nested.createListItem(["Build and test"]),
], { classes: ["steps-list"] });

Definition lists

nested.createDefinitionList(children, options?, id?): string        // <dl>
nested.createDefinitionTerm(children, options?, id?): string        // <dt>
nested.createDefinitionDescription(children, options?, id?): string // <dd>
const dl = nested.createDefinitionList([
  nested.createDefinitionTerm(["FDO"]),
  nested.createDefinitionDescription(["FlexDevOps — A desktop application framework"]),
  nested.createDefinitionTerm(["SDK"]),
  nested.createDefinitionDescription(["Software Development Kit"]),
], { classes: ["glossary"] });

DOMMisc

DOMMisc provides miscellaneous elements. Currently it exposes a divider() method that renders a styled <hr>.
import { DOMMisc } from "@anikitenko/fdo-sdk";
const misc = new DOMMisc();
divider(options?: Partial<typeof DOM.DEFAULT_OPTIONS>, id?: string): string
The default style is a 1px top border (#cccccd) with 10px margin. Override with options.style:
const misc = new DOMMisc();

const separator = misc.divider({
  style: { borderTop: "2px solid #2563EB", margin: "24px 0" },
});

Full composition example

The following is taken from examples/05-advanced-dom-plugin.ts and shows how the helper classes work together in a complete render() method:
import {
  DOMButton, DOMInput, DOMLink, DOMNested,
  DOMSemantic, DOMTable, DOMText,
  FDO_SDK, FDOInterface, PluginMetadata,
} from "@anikitenko/fdo-sdk";

export default class AdvancedDOMPlugin extends FDO_SDK implements FDOInterface {
  private readonly _metadata: PluginMetadata = {
    name: "Advanced DOM Example",
    version: "1.0.0",
    author: "FDO SDK Team",
    description: "Demonstrates advanced composition with DOM helper classes",
    icon: "widget",
  };

  get metadata(): PluginMetadata { return this._metadata; }

  init(): void {
    this.info("AdvancedDOMPlugin initialized", { plugin: this._metadata.name });
  }

  render(): string {
    const text   = new DOMText();
    const nested = new DOMNested();
    const semantic = new DOMSemantic();
    const table  = new DOMTable();
    const button = new DOMButton();
    const input  = new DOMInput("username-input", {
      style: { padding: "8px", border: "1px solid #ccc", borderRadius: "4px", width: "280px" },
    });
    const link   = new DOMLink("docs-link", { style: { color: "#0b65d8", textDecoration: "none" } });

    const thead = table.createTableHead([
      table.createTableRow([
        table.createTableHeader([text.createStrongText("Environment")]),
        table.createTableHeader([text.createStrongText("Status")]),
        table.createTableHeader([text.createStrongText("Latency")]),
      ]),
    ]);

    const tbody = table.createTableBody([
      table.createTableRow([
        table.createTableCell(["Production"]),
        table.createTableCell([
          text.createSpanText("Healthy", { style: { color: "#1f8a3d", fontWeight: "600" } }),
        ]),
        table.createTableCell(["42ms"]),
      ]),
    ]);

    const dataTable = table.createTable(
      [table.createCaption([text.createStrongText("Runtime Health Snapshot")]), thead, tbody],
      { style: { width: "100%", borderCollapse: "collapse", marginTop: "12px" } },
      "health-table"
    );

    const formSection = nested.createForm(
      [
        text.createLabelText("Operator name", "username-input", {
          style: { display: "block", marginBottom: "6px", fontWeight: "600" },
        }),
        input.createInput("text"),
        nested.createBlockDiv(
          [
            button.createButton("Register Session", () => {}, {
              style: {
                marginTop: "12px", padding: "8px 12px", borderRadius: "4px",
                border: "1px solid #0b65d8", color: "#0b65d8",
                backgroundColor: "#eef5ff", cursor: "pointer",
              },
            }, "register-session-button"),
          ],
          { style: { marginTop: "8px" } }
        ),
      ],
      {
        customAttributes: { onsubmit: "event.preventDefault();" },
        style: { padding: "12px", border: "1px solid #d9e2ef", borderRadius: "6px", marginTop: "14px" },
      }
    );

    return semantic.createMain(
      [
        semantic.createHeader([
          text.createHText(1, this._metadata.name),
          text.createPText(this._metadata.description, { style: { color: "#667085" } }),
        ]),
        semantic.createSection([text.createHText(2, "Health Table"), dataTable], {
          style: { marginTop: "14px" },
        }),
        semantic.createSection([text.createHText(2, "Operator Form"), formSection], {
          style: { marginTop: "18px" },
        }),
        semantic.createFooter(
          [text.createPText("Need more details?"), link.createLink("Open plugin author docs", "https://plugins.fdo.alexvwan.me")],
          { style: { marginTop: "20px", paddingTop: "10px", borderTop: "1px solid #e5e7eb" } }
        ),
      ],
      { style: { padding: "20px", fontFamily: "system-ui, -apple-system, Segoe UI, sans-serif", lineHeight: "1.5" } }
    );
  }
}

new AdvancedDOMPlugin();