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 Degradation during SSR

  • LiveNode / Live: Evaluates its builder closure exactly once during the render pass. No signal subscriptions or reactive effect listeners are retained on the server.
  • ShowNode / Show: Evaluates its when() predicate closure once. Renders child if true or fallback if false.
  • ForEachNode / ForEach: Evaluates its items() collection closure once and renders each item via builder to static HTML.
  • MountNode / Mount: Renders its child directly; lifecycle callbacks (onMount, onUnmount) are ignored during SSR.
  • RefNode: Renders its child; DOM references are not attached during SSR.
  • ContextProviderNode: Provides ambient context values down the subtree using Dart Zones.
  • ErrorBoundaryNode: Renders builder(); if an exception is thrown, synchronously renders fallback(error, stack).
  • PortalNode: Emits <template data-bloom-portal="..."> enclosing the portal subtree.
  • SuspenseNode: In synchronous renderToHtml, renders the fallback node only. For asynchronous out-of-order streaming of Suspense boundaries, use renderToStreamWithSuspense.

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.
  • 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>{}});
}