Polotno
Export & Import

HTML Export

Export Polotno designs to HTML from plain design JSON

Overview

The @polotno/html-export package converts a Polotno design into an HTML string. It works directly on plain design JSON: no running editor or store instance is required: so you can export a saved design, or export from a page that never mounts the full editor.

The exporter is browser-first. In Node.js 22.13 or newer it runs through its /node entry (see Using in Node); for pixel-accurate server-side rendering use polotno-node.

Replaces store.toHTML()

This standalone package is the recommended way to export HTML. The editor's store.toHTML() / store.saveAsHTML() methods are deprecated and now delegate to jsonToHTML internally: migrate to the package directly.

Installation

npm install @polotno/html-export

Basic Usage

Pass the design JSON (from store.toJSON(), a saved file, or any source) to jsonToHTML:

import { jsonToHTML } from '@polotno/html-export';

const html = await jsonToHTML(store.toJSON());

jsonToHTML returns a Promise<string> containing the rendered HTML.

API Reference

jsonToHTML(json, options?)

Renders a Polotno design into an HTML string.

Parameters:

  • json (required): plain design JSON (e.g. from store.toJSON()).
  • options (optional):
    • key: your Polotno API key, required for production use.
    • elementHook({ dom, element }): post-process each element's virtual node before it is serialized. dom is a lightweight JSX-like object with type, props, and children; mutate and return it.
    • textOverflow: the global mode for text without its own textOverflow: 'change-font-size' (default, shrinks the font to fit), 'resize', 'ellipsis' or 'fit'. An element's own textOverflow and maxLines apply either way; minFontSize and maxFontSize bound 'fit' only. See Text Sizing.
    • textSplitAllowed: boolean (default false); whether shrink-to-fit measurement may wrap a long word mid-word.
    • fetchGuard: (url) => boolean | Promise<boolean>, called for every URL the export downloads to inline (SVG sources and clip masks) and, in Node, the font files it measures text with, including each redirect hop in Node (a browser shows it only the first and final URL); return false to reject it. It replaces the default check, which in Node refuses only cloud-metadata endpoints.
import { jsonToHTML } from '@polotno/html-export';

const html = await jsonToHTML(store.toJSON(), {
  elementHook: ({ dom, element }) => {
    // add a custom class to every element
    dom.props.className = `element-${element.type}`;
    return dom;
  },
});

jsonToDOM(json, options?)

Same as jsonToHTML but returns the DOM tree instead of a serialized string, useful when you want to mount or further manipulate the result in the browser.

Using in Node

In Node, import @polotno/html-export/node and install its two optional peers. It needs no jsdom or browser globals: linkedom parses, and @napi-rs/canvas measures text in the fonts the design uses. The root entry is for browsers.

npm install @polotno/html-export linkedom @napi-rs/canvas
import { jsonToHTML } from '@polotno/html-export/node';

const html = await jsonToHTML(designJson);

Full-fidelity Node rendering

Node cannot decode video, so a design with a video element fails with VIDEO_FAILED. For pixel-accurate rendering in Node with real Chromium, use polotno-node.

Limitations

Not pixel-perfect

HTML export may not reproduce every element or effect exactly. For pixel-perfect output use PNG/JPEG (store.toDataURL()) or PDF export.

If you hit a missing feature, share it in the Polotno Community.

On this page