renderToHtml function

String renderToHtml(
  1. BloomNode node
)

Renders a BloomNode descriptor tree synchronously to an HTML string.

This is the primary server-side rendering (SSR) and static site generation (SSG) entry point. It executes entirely in pure Dart and requires no browser DOM, Flutter runtime, or JS interop.

Reactive Node Hydration Markers during SSR

  • LiveNode / Live: Evaluates its builder closure exactly once and wraps the output in <!--bloom:live--> markers. No signal subscriptions are retained on the server; the browser hydrates the existing nodes.
  • MemoNode / Memo: Evaluates once, wrapped in <!--bloom:memo-->.
  • ShowNode / Show: Evaluates its when() predicate once, renders the active branch wrapped in <!--bloom:show--> markers.
  • ForEachNode / ForEach: Evaluates its items() collection once. Keyed lists wrap each item in <!--bloom:key=<key>--> markers inside a <!--bloom:foreach--> boundary so hydration can reconcile by key.
  • ErrorBoundaryNode: Renders builder() wrapped in <!--bloom:error-boundary-->; on exception renders fallback instead.
  • SuspenseNode: In synchronous renderToHtml, renders the fallback wrapped in <!--bloom:suspense--> markers. For asynchronous out-of-order streaming of Suspense boundaries, use renderToStreamWithSuspense.
  • MountNode / Mount: Renders its child directly; lifecycle callbacks (onMount, onUnmount) are ignored during SSR (hydration runs onMount).
  • RefNode: Renders its child; DOM references are not attached during SSR.
  • ContextProviderNode: Provides ambient context values down the subtree using Dart Zones.
  • PortalNode: Emits <template data-bloom-portal="..."> enclosing the portal subtree.

Tag and Attribute Validation & Security

  • Tag names and attribute names are strictly validated against alphanumeric identifier patterns and will throw an ArgumentError if an invalid name is encountered.
  • Text content, class names, styles, and attribute values are automatically escaped via escapeHtml.
  • Inline event attributes, srcdoc, and executable URL schemes are rejected; use the typed on: event map for handlers.
  • Void elements (e.g. <img>, <input>, <br>, <meta>, <link>) are emitted without closing tags.
final html = renderToHtml(
  Div(
    className: 'user-profile',
    children: [
      const H1(text: 'Account Details'),
      P(text: 'Welcome, Alice'),
    ],
  ),
);

Implementation

String renderToHtml(BloomNode node) {
  return runZoned(() {
    final buf = StringBuffer();
    _render(node, buf);
    return buf.toString();
  }, zoneValues: {_keyframesZoneKey: <String>{}});
}